【问题标题】:Regular Expressions and negating a whole character group [duplicate]正则表达式和否定整个字符组[重复]
【发布时间】:2010-11-01 21:53:08
【问题描述】:

我正在尝试一些我认为对我来说应该相当明显的事情,但事实并非如此。我正在尝试匹配一个不包含特定字符序列的字符串。我尝试过使用[^ab][^(ab)] 等来匹配不包含'a's 或'b's,或者只有'a's 或只有'b's 或'ba' 但不匹配'ab' 的字符串。我给出的示例与“ab”不匹配,这是真的,但它们也不会单独匹配“a”,我需要它们。有没有一些简单的方法可以做到这一点?

【问题讨论】:

标签: regex


【解决方案1】:

使用诸如[^ab] 之类的字符类将匹配不在字符集中的单个字符。 (^ 是否定部分)。

要匹配不包含多字符序列ab 的字符串,您需要使用否定前瞻:

^(?:(?!ab).)+$


而上面在正则注释模式下剖析的表达式是:

(?x)    # enable regex comment mode
^       # match start of line/string
(?:     # begin non-capturing group
  (?!   # begin negative lookahead
    ab  # literal text sequence ab
  )     # end negative lookahead
  .     # any single character
)       # end non-capturing group
+       # repeat previous match one or more times
$       # match end of line/string

【讨论】:

  • 剖析正则表达式对我很有帮助。谢谢。
  • ..替换它,可能只是^((?!ab).+)$
  • 一个小笔记。 “任何单个字符”中的. 仅用于同一行。如果您需要对多行正则表达式执行此操作,则可能需要将其替换为(.|\n)
【解决方案2】:

使用负前瞻:

^(?!.*ab).*$

更新:在下面的 cmets 中,我指出这种方法比Peter's answer 中给出的方法慢。从那以后我进行了一些测试,发现它确实稍微快了一点。然而,之所以喜欢这种技术而不是另一种技术的原因不是速度,而是简单。

另一种技术,将here 描述为 tempered greedy token,适用于更复杂的问题,例如匹配分隔符由多个字符组成的分隔文本(如 HTML,正如 Luke 评论的 @ 987654323@)。对于问题中描述的问题,它是矫枉过正的。

对于任何感兴趣的人,我用大量 Lorem Ipsum 文本进行了测试,计算了不包含单词“quo”的行数。这些是我使用的正则表达式:

(?m)^(?!.*\bquo\b).+$

(?m)^(?:(?!\bquo\b).)+$

无论我是在整个文本中搜索匹配项,还是将其分成几行并单独匹配它们,锚定前瞻始终优于浮动前瞻。

【讨论】:

  • 我相信这样更有效率:(?:(?!ab).)*
  • 还想使用开始/结束标记来强制检查整个字符串。
  • @Blixit:是的,是的。但它也更难阅读,特别是对于正则表达式新手。我发布的那个对于大多数应用程序来说已经足够高效了。
  • 不要写针对新手的代码!如果代码难以阅读,请留下 cmets/文档以便他们学习,而不是使用让他们无知的较少代码。
  • 如果我认为这两种方法之间会有显着差异,我会毫不犹豫地推荐更快的一种。另一方面,正则表达式是如此不透明(如果不是神秘的话),我认为尽可能将知识分解成更小、更易于管理的块是值得的。
【解决方案3】:

是的,它称为负前瞻。它是这样的 - (?!regex here)。所以abc(?!def) 将匹配 abc not 后跟 def。所以它会匹配 abce、abc、abck 等。

同样有积极的前瞻 - (?=regex here)。所以abc(?=def) 将匹配 abc 后跟 def。

也有消极和积极的后视——分别是(?<!regex here)(?<=regex here)

需要注意的一点是,负前瞻是零宽度。也就是说,它不算占用任何空间。

所以看起来a(?=b)c 会匹配“abc”,但它不会。它将匹配'a',然后是'b'的正向前瞻,但它不会向前移动到字符串中。然后它将尝试将 'c' 与 'b' 匹配,但这是行不通的。同样,^a(?=b)b$ 将匹配 'ab' 而不是 'abb',因为环视是零宽度(在大多数正则表达式实现中)。

this 页面上的更多信息

【讨论】:

  • 引用“lookbehind”运算符也很有用,并非所有在线正则表达式解析器/文档都会包含它,即使它有效且有效。
【解决方案4】:

abc(?!def) 将匹配 abc not follow 按定义。所以它会匹配 abce, abc, abck 等 如果我不想要 def xyz 也不会是 abc(?!(def)(xyz)) ???

我有同样的问题并找到了解决方案:

abc(?:(?!def))(?:(?!xyz))

这些非计数组由“AND”组合,所以这应该可以解决问题。希望对您有所帮助。

【讨论】:

  • 那句话出自哪里?只有一部分来自this Answer。除此之外,您还没有回答问题,但似乎已经回答了您尚未链接到的内容。我认为abc(?:(?!def)(?!xyz)) 可以。他们已经在抓捕组了。无需在其中放置另一个。它们也不是“由“AND”组合而成的”。一次检查一个,就像首先检查 ab 时检查 a,然后检查 b,但前瞻只是不要移动光标。
【解决方案5】:

使用您所描述的正则表达式是一种简单的方法(据我所知)。如果你想要一个范围,你可以使用 [^a-f]。

【讨论】:

    【解决方案6】:

    最简单的方法是将否定完全从正则表达式中提取出来:

    if (!userName.matches("^([Ss]ys)?admin$")) { ... }
    

    【讨论】:

    • 虽然这在您使用 just 表达式时很有用,但作为更大表达式的一部分,Peter 描述的否定前瞻方法允许在单个字符串中同时出现肯定和否定条件.
    • 绝对正确。但问题是“匹配一个不包含特定字符序列的字符串”。我认为为此目的,消极的前瞻是矫枉过正的。
    • 如果您使用的是文本编辑器,则无法执行此操作。
    • 如果您在编程语言之外使用正则表达式(如 Apache 或 Nginx 配置...
    【解决方案7】:

    只需在字符串中搜索“ab”,然后否定结果:

    !/ab/.test("bamboo"); // true
    !/ab/.test("baobab"); // false
    

    这似乎更容易,也应该更快。

    【讨论】:

      【解决方案8】:

      在这种情况下,我可能只是完全避免使用正则表达式,而是使用类似的东西:

      if (StringToTest.IndexOf("ab") < 0)
        //do stuff
      

      这也可能会快得多(上面对正则表达式的快速测试表明,这种方法大约需要正则表达式方法的 25% 的时间)。一般来说,如果我知道我正在寻找的确切字符串,我会发现正则表达式是矫枉过正的。既然您知道您不想要“ab”,那么无需使用正则表达式即可测试字符串是否包含该字符串是一件简单的事情。

      【讨论】:

      • 这是一个好点!如果序列是一个简单的字符串,那么正则表达式会使事情变得过于复杂; contains/indexOf 检查是更明智的选择。
      【解决方案9】:

      正则表达式 [^ab] 将匹配例如 'ab ab ab' 但不匹配 'ab',因为它将匹配字符串 'a' 或 'b'。

      你有什么语言/场景?你能从原始集合中减去结果,然后匹配 ab 吗?

      如果您正在使用 GNU grep,并且正在解析输入,请使用“-v”标志来反转结果,返回所有不匹配的内容。其他正则表达式工具也具有“返回不匹配”功能。

      如果我理解正确,除了那些在任何地方包含“ab”的项目之外,你想要所有东西。

      【讨论】:

      • "正则表达式 [^ab] 将匹配例如 'ab ab ab' 但不匹配 'ab',因为它将匹配字符串 'a' 或 'b'。"。这似乎是不正确的。 [^ab] 是一个字符类,它匹配除 a 和 b 之外的所有内容。显然它会匹配空格。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-05-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-06
      相关资源
      最近更新 更多