【问题标题】:Regex: match pattern as long as it's not in the beginning正则表达式:匹配模式,只要它不在开头
【发布时间】:2013-03-18 03:59:09
【问题描述】:

假设以下字符串:

aaa bbb ccc
bbb aaa ccc

我想匹配aaa,只要它不在字符串的开头。我试图通过这样做来否定它:

[^^]aaa

但我认为这是不对的。使用preg_replace

【问题讨论】:

  • 你只匹配aaa吗?换成什么?

标签: regex regex-negation


【解决方案1】:

您可以使用向后看来确保它不是在开头。 (?<!^)aaa

【讨论】:

  • 无论如何否定位置断言?
  • 我还需要捕获aaa。用括号括起来吗?
  • 仅 JavaScript 使用 (?!^)aaa
  • 如果您在 R 中使用 gsub() 执行此操作,则如果您设置了 perl = T 选项,它就可以工作
【解决方案2】:

因为我是通过 Google 搜索来到这里的,并且对不使用后视的解决方案感兴趣,所以这是我的 2 美分。

[^^]aaa 模式匹配除^ 以外的字符,然后匹配字符串中的 3 个as 任何地方[^...]negated character class,其中 ^ 不被视为特殊字符。请注意,紧跟在[ 之后的第一个^ 是特殊的,因为它表示否定,而第二个只是文字插入符号。

因此,^ 不能在 [...] 内表示字符串的开头。

一种解决方案是使用任何否定的环视,这两个效果一样好:

(?<!^)aaa

和前瞻:

(?!^)aaa

为什么前瞻也有效? Lookarounds 是零宽度断言,锚点也是零宽度——它们不消耗文本。从字面上看,(?&lt;!^) 检查当前位置左侧是否没有字符串开始位置,(?!^) 检查当前位置右侧是否没有字符串开始位置。正在检查相同的位置,这就是为什么两者都能正常工作的原因。

【讨论】:

  • 感谢前瞻替代方案,因为 Javascript 尚不支持后瞻。
  • ECMAScript 2018+ 中已经引入了lookbehind 支持,因此您可以在Node.JS 和Chrome 中使用(?&lt;!^),但(?!^) 在遵循ES5 标准或更早版本的VBA 中仍然很好JS环境,包括IE。
  • Lookbehinds 仅在 Chrome 62+ 和 Opera 49+ 中受支持 (caniuse.com/#feat=js-regexp-lookbehind)
【解决方案3】:

如果您不想使用lookbehind,请使用此正则表达式:

/.(aaa)/

并使用matched group # 1

【讨论】:

  • 这是最好的答案,因为它也适用于正则表达式的其他方言。
  • 但除非您的正则表达式引擎支持重叠匹配,否则它不会匹配多次出现的aaaxaaaaaa 将只有一个匹配项。
【解决方案4】:

这是我第一次看到lookarounds 的表现优于\K。很有趣。

通常捕获组和环视需要额外的步骤。但是由于这项任务的性质,正则表达式引擎可以更快地导航字符串以搜索aaa,然后再回头寻找字符串锚点的开始。

我将添加几个\K 模式进行比较。

我使用s 模式修饰符以防前导字符可能是换行符(. 通常不会匹配)。我只是想我会添加这个考虑来抢先解决我可能会提出的边缘案例。

同样,这是一个启发性的场景,因为在我处理过的所有其他正则表达式案例中,\K 击败了其他技术。

步数比较矩阵:

              | `~.\Kaaa~s` | `~.+?\Kaaa~s` | `(?<!^)aaa` | `(?!^)aaa` | `.(aaa)` |
--------------|-------------|---------------|-------------|------------|----------|
`aaa bbb ccc` |   12 steps  |    67 steps   |   8 steps   |  8 steps   | 16 steps |
--------------|-------------|---------------|-------------|------------|----------|
`bbb aaa ccc` |   15 steps  |    12 steps   |   6 steps   |  6 steps   | 12 steps |

要点是:要了解您的模式的效率,请将它们发送到 regex101.com 并比较步数。

另外,如果您知道您正在寻找什么子字符串并且您不需要正则表达式模式,那么您应该使用 strpos() 作为最佳实践(只需检查返回值为&gt; 0)

...换句话说:

if (strpos($haystack, 'aaa')) {
    // 'aaa' is "truthy"
    // 'aaa' is found and not positioned at offset zero
}

【讨论】:

  • 关于检查 regex101.com 中正则表达式模式效率的有用建议。
【解决方案5】:

这将有助于找到您正在寻找的东西:

(?&lt;!^)aaa

使用示例:http://regexr.com?34ab2

【讨论】:

    【解决方案6】:

    我来到这里是为了寻找 re2 引擎的解决方案,该引擎被 google 电子表格使用,它不支持环视。 但是这里的答案给了我使用以下内容的想法。 我不明白为什么我必须用捕获的组替换,但无论如何,它有效。

    aaa bbb ccc
    bbb aaa ccc

    ([^^])aaa
    

    替换为:

    $1zzz
    

    结果:

    aaa bbb ccc
    bbb zzz ccc

    【讨论】:

      猜你喜欢
      • 2019-06-01
      • 1970-01-01
      • 2013-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-25
      相关资源
      最近更新 更多