【问题标题】:Regular expressions: Ensuring b doesn't come between a and c正则表达式:确保 b 不在 a 和 c 之间
【发布时间】:2016-05-15 15:53:40
【问题描述】:

这是我试图用正则表达式做的事情,但我不知道怎么做。我有一个大文件,字符串 abc123xyz 在整个文件中出现多次。

我想要一个正则表达式来匹配以abc 开头、在中间某处包含123、以xyz 结尾的大文件的子字符串,并且没有其他@987654328 实例@ 或 xyz 在除开头和结尾之外的子字符串中。

用正则表达式可以吗?

【问题讨论】:

标签: regex python-2.7


【解决方案1】:

当您的左右分隔符是单个字符时,可以使用negated character classes 轻松解决。因此,如果您的匹配在 ac 之间并且不应包含 b字面意思),您可以使用 (demo)

a[^abc]*c

当您想确保在 最接近的 ac (demo) 之间有一个 b 时,这与您使用的技术相同:

a[^abc]*b[^ac]*c

当您的左右分隔符是多字符串时,您需要一个tempered greedy token

abc(?:(?!abc|xyz|123).)*123(?:(?!abc|xyz).)*xyz

regex demo

为确保它跨行匹配,请在编译正则表达式时使用re.DOTALL 标志。

请注意,要使用如此繁重的模式获得更好的性能,您应该考虑展开它。它可以通过否定字符类和否定前瞻来完成。

模式详情

  • abc - 匹配 abc
  • (?:(?!abc|xyz|123).)* - 匹配任何不是 abcxyz123 字符序列起点的字符
  • 123 - 文字字符串 123
  • (?:(?!abc|xyz).)* - 不是abcxyz 字符序列起点的任何字符
  • xyz - 一个尾随子字符串 xyz

参见下图(如果使用re.S. 将表示AnyChar):

Python demo

import re
p = re.compile(r'abc(?:(?!abc|xyz|123).)*123(?:(?!abc|xyz).)*xyz', re.DOTALL)
s = "abc 123 xyz\nabc abc 123 xyz\nabc text 123 xyz\nabc text xyz xyz"
print(p.findall(s))
// => ['abc 123 xyz', 'abc 123 xyz', 'abc text 123 xyz']

【讨论】:

  • 能否请您链接生成该状态机的站点?我知道存在一个具有类似 UI 的网站,但找不到它。对不起,不相关的评论。我会尽快删除它:)
  • 为什么是|123
  • @StefanPochmann 好吧,如果你在第一种情况下使用惰性量词,你可能会摆脱它:r'abc(?:(?!abc|xyz).)*?123(?:(?!abc|xyz).)*xyz'。它的工作原理类似。
  • 不过,两者都只是优化,对吧?没必要?
  • 嘿@WiktorStribiżew 我认为您的第一个段落中的意思是“a 和 c 之间”。我尝试对其进行编辑,但我不想添加噪音来完成 6 个字符规则。
【解决方案2】:

使用 PCRE 的解决方案是:

这使用m 标志。如果您只想从一行的开头和结尾检查,请分别在开头和结尾添加 ^$

abc(?!.*(abc|xyz).*123).*123(?!.*(abc|xyz).*xyz).*xyz

Debuggex Demo

【讨论】:

  • 用什么软件画图
  • @Er.AmitJoshi 这不是软件,是Debuggex Site 答案中有链接
【解决方案3】:

hvdcomment 非常合适,这只是提供了一个示例。例如,在 SQL 中,我认为这样做会更清楚:

where val like 'abc%123%xyz' and
      val not like 'abc%abc%' and
      val not like '%xyz%xyz'

我想在其他环境中很容易做类似的事情。

【讨论】:

    【解决方案4】:

    你可以使用环视。

    /^abc(?!.*abc).*123.*(?<!xyz.*)xyz$/g
    

    (我没有测试过。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-01-10
      • 2019-03-11
      相关资源
      最近更新 更多