【问题标题】:Regex negative lookbehind on string正则表达式否定后向字符串
【发布时间】:2014-04-19 02:07:17
【问题描述】:

如果一个字符串存在但不是立即在另一个字符串之前,我似乎无法找到不返回匹配项的方法。

如果一个字符串存在于另一个字符串之前立即,我无法返回匹配项,如下所示。

$string = 'Stackoverflow hello world foobar test php';

$regex = "~(Stackoverflow).*?(?<!(test\s))(php)~i";

if(preg_match_all($regex,$string,$match))
    print_r($match);

在这个例子中,如果我们有单词 Stackoverflowphp 我们想要返回一个匹配,但前提是单词 test(带有空格字符)在单词 php 之前不存在。

这不会返回任何好的结果。

现在让我说我想匹配 php 但前提是 foobar 这个词在 Stackoverflowphp 之间的某处不存在,我以为我可以做到以下几点。

$string = 'Stackoverflow hello world foobar test php';

$regex = "~(Stackoverflow).*?(?<!(foobar)).*?(php)~i";

if(preg_match_all($regex,$string,$match))
    print_r($match);

(我已将字符串后面的负面外观更改为(foobar),并在后面添加了.*?)

我还想说,我不能总是知道foobarphp之间会存在什么词,有时没有,有时200个,但我确实有一些定位信息(在Stackoverflow之后和php之前)。

【问题讨论】:

  • .*? 中的任何一个都可以绕过断言。您需要使用负前瞻来掩盖 . 任何占位符的所有可能位置。
  • @mario 所以我必须在 Stackoverflow 之后为每个字符重复这个 (?
  • "这不会返回任何好的结果。" == "一个太快的假设"
  • 是的,基本上你将.*? 中的句点拆分为一个掩码匹配所有((?!foobar).),并用((?!xxx).)*? 反复测试。它通常被认为是浪费的,因为断言适用于介于两者之间的每个字符。但对于简单的情况,它是相当可行的,PCRE 对其进行了优化。

标签: php regex pcre


【解决方案1】:

您的第二个正则表达式有效,因为“foobar”可以作为.*? 的一部分出现。具体来说,第一个.*?会匹配空字符串“”,第二个会匹配“hello world foobar test”,前面确实没有“foobar”!

要获得所需的结果,一种方法是查看每个字符并确保它不是“f”,或者如果它是“f”且后面没有“o” ,或者如果它是一个“f”后跟一个“o”,那么它后面没有另一个“o”,等等。

这会给你留下:

$string = 'Stackoverflow hello world foobar test php';

$regex = "~(Stackoverflow)(?:[^f]|f[^o]|fo[^o]|foo[^b]|foob[^a]|fooba[^r])*?(php)~i";

if(preg_match_all($regex,$string,$match))
    print_r($match);

性能更新

我对我的建议和 Ron 的建议进行了基准测试,发现虽然在 Perl 中没有显着差异,但他在 PCRE 中的速度快了近 50%。

【讨论】:

  • 这是一个有趣的答案,但我认为线程 mario 中的答案可能更实用,但我仍在测试它以确保我没有忽略任何东西。谢谢。
  • 您好,我测试了您的答案,发现它有效,但我不明白它为什么有效。在(Stackoverflow)之后,我认为我们必须告诉正则表达式可能会出现一些未知字符,所以直接在(Stackoverflow)之后我们将放置“.*”。我不明白正则表达式是如何在 (SO).... 和 (FB).... 之间跳过“hello world”的。我的假设是错误的,但我不知道为什么。
  • 没关系,我找到了为什么它可以从另一个用户那里工作的原因。谢谢
【解决方案2】:

我会使用负前瞻来确保字符串 'foobar.*php' 在 'stackoverflow' 之后不存在并且由于您想捕获 php,我会将其放入捕获组中。比如:

Stackoverflow(?:(?!foobar.*php).)*(php)

请注意,这会导致在每个字符之后进行检查

【讨论】:

    猜你喜欢
    • 2012-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-12
    • 2012-02-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多