正则表达式的可变长度后视断言替代方案

IT技术 php javascript python regex perl
2021-01-24 15:18:07

在 Python/PHP/JavaScript 中是否有支持可变长度后视断言的正则表达式实现?

/(?<!foo.*)bar/

如何编写具有相同含义但不使用后视断言的正则表达式?

这种类型的断言是否有可能在某一天实施?

事情比我想象的要好得多。

更新:

(1) 已经有支持变长后视断言的正则表达式实现。

Python module正则表达式(不是标准的re,而是附加regexmodule)支持这样的断言(并且有许多其他很酷的特性)。

>>> import regex
>>> m = regex.search('(?<!foo.*)bar', 'f00bar')
>>> print m.group()
bar
>>> m = regex.search('(?<!foo.*)bar', 'foobar')
>>> print m
None

正则表达式中有一些 Perl 不能做而 Python 可以做的事情,这对我来说真的是一个很大的惊喜。也许,Perl 也有“增强的正则表达式”实现?

(感谢并为 MRAB +1)。

(2)\K现代正则表达式有一个很酷的特性

这个符号意味着当你进行替换时(在我看来,断言最有趣的用例是替换),之前找到的所有字符\K都不能改变。

s/unchanged-part\Kchanged-part/new-part/x

这几乎就像一个后视断言,但当然不是那么灵活。

更多关于\K

据我了解,您不能在同一个正则表达式中使用 \K 两次。而且你不能说到什么时候你想“杀死”你找到的角色。那总是直到行的开头。

(感谢并为池上 +1)。

我的补充问题:

  • 是否可以说哪一点必须是最终的\K效果
  • Perl/Ruby/JavaScript/PHP 的增强正则表达式实现怎么样?类似于regexPython 的东西
5个回答

大多数情况下,您可以使用\K.

s/(?<=foo.*)bar/moo/s;

将是

s/foo.*\Kbar/moo/s;

直到最后\K遇到的任何东西都不被视为匹配的一部分(例如,出于替换目的$&,等)

负向后视有点棘手。

s/(?<!foo.*)bar/moo/s;

将是

s/^(?:(?!foo).)*\Kbar/moo/s;

因为(?:(?!STRING).)*STRING[^CHAR]*CHAR


如果您只是匹配,您甚至可能不需要\K.

/foo.*bar/s

/^(?:(?!foo).)*bar/s
这太好了,非常感谢。但请添加一个关于\K实际情况的注释对谷歌来说并不容易。
2021-03-20 15:18:07
捕获是显而易见的,但它并不有趣:)\K好多了 :)
2021-03-26 15:18:07
这个技巧\K真的很酷,但是是否可以\K在一个正则表达式中指定多个可能不是
2021-03-28 15:18:07
不(或没有用),但您可以使用捕获:s/foo.*\Kbar/moo/s;=== s/(foo.*)bar/${1}moo/s;
2021-04-05 15:18:07
但你只能拥有一个。我是在指出如果您要求的不止一个,您可以做什么。(在 5.10\K引入之前,捕获也有效。)
2021-04-06 15:18:07

对于 Python,有一个支持可变长度lookbehinds的正则表达式实现:

http://pypi.python.org/pypi/regex

它旨在与标准 re module向后兼容。

此答案已添加到Stack Overflow 正则表达式常见问题解答中的“Lookarounds”下。
2021-03-16 15:18:07
工作顺利Python 3.4.1它似乎也比 快一点re
2021-03-21 15:18:07
谢谢!这确实有效,并且该module通常非常有趣。非常感谢你!+1
2021-03-28 15:18:07

您可以反转字符串和模式并使用可变长度前瞻

(rab(?!\w*oof)\w*)

粗体匹配:

raboof rab7790oof raboo rabof rab rabo raboooof rabo

据我所知,原始解决方案是:

Jeff 'japhy' Pinyan

本杰明,谢谢你的回答,但你确定可以逆转任何模式吗?
2021-03-18 15:18:07
此答案已添加到Stack Overflow 正则表达式常见问题解答中的“Lookarounds”下。
2021-03-25 15:18:07
我从来没有遇到过这不起作用的情况。创建模式比“正常”模式需要更多的时间。
2021-04-05 15:18:07

告诉你的正则表达式将找到的任何实例bar这是不是前面有foo

一个简单的替代方法是首先匹配foo字符串,然后找到第一次出现的索引。然后搜索bar,看看是否可以找到出现该索引之前的事件

如果你想找到的情况下,bar直接通过之前foo,我还可以提供一个正则表达式(不使用回顾后),但它会非常难看。基本上,颠倒/foo/- 即的意义/[^f]oo|[^o]o|[^o]|$/

亚历克斯,谢谢你的回答,但总的来说,一切都没有你写的那么简单。我只提供了一个带有断言的正则表达式的小例子。当然,re 可能要复杂得多,而且断言可能深入其中。在这种情况下,您不能只是简单地检查某个字符串中的某个子字符串。
2021-04-02 15:18:07
亚历克斯,当您需要“bar其前面没有直接使用的实例foo”时,您可以使用普通的lookbehind assertion (?<!foo)bar这样可行。但诀窍是 foo 和 bar 之间可以是其他字符。
2021-04-09 15:18:07
foo.*|(bar)

如果foo首先在字符串中,则正则表达式将匹配,但不会有组。

否则,它将查找bar并将其分配给一个组。

因此,您可以使用此正则表达式并在找到的组中查找结果:

>>> import re
>>> m = re.search('foo.*|(bar)', 'f00bar')
>>> if m: print(m.group(1))
bar
>>> m = re.search('foo.*|(bar)', 'foobar')
>>> if m: print(m.group(1))
None
>>> m = re.search('foo.*|(bar)', 'fobas')
>>> if m: print(m.group(1))
>>> 

来源。