正则表达式的可变长度后向断言替代方案
- 2025-03-21 09:07:00
- admin 原创
- 38
问题描述:
Python/PHP/JavaScript 中是否有支持可变长度后向断言的正则表达式实现?
/(?<!foo.*)bar/
我如何编写一个具有相同含义但不使用后向断言的正则表达式?
这种论断有朝一日有可能实现吗?
事情比我想象的要好得多。
更新:
(1)已经有支持可变长度后向断言的正则表达式实现。
Python 模块regex(不是标准re
,而是附加regex
模块)支持这样的断言(并且还有许多其他很酷的功能)。
>>> 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)。
K
(2)现代正则表达式有一个很酷的功能。
这个符号的意思是当你进行替换时(从我的角度来看,断言最有趣的用例是替换),所有之前找到的字符K
都不能改变。
s/unchanged-partKchanged-part/new-part/x
这几乎就像一个后视断言,但当然不是那么灵活。
更多信息K
:
Perl 正则表达式 \K 技巧
PCRE 正则表达式聚焦:\K
据我所知,您不能在同一个正则表达式中使用 \K 两次。而且您无法指定要“删除”找到的字符到哪个位置。这始终是到行首为止。
(感谢 ikegami 并+1)。
我的附加问题:
能否说出哪一点必须是最终的
K
效果点?那么 Perl/Ruby/JavaScript/PHP 的增强正则表达式实现怎么样?类似于
regex
Python。
解决方案 1:
大多数情况下,您可以通过使用来避免可变长度后视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
解决方案 2:
对于 Python,有一个支持可变长度后视的正则表达式实现:
http://pypi.python.org/pypi/regex
它的设计目的是与标准 re 模块向后兼容。
解决方案 3:
您可以反转字符串和模式并使用可变长度前瞻
(rab(?!w*oof)w*)
匹配项以粗体显示:
拉布·拉布7790oof拉布·拉布 ·拉布 ·拉布· 拉布·拉布
据我所知,原始解决方案是:
Jeff 'japhy' Pinyan
解决方案 4:
您显示的正则表达式将找到任何前面bar
没有的foo
实例。
一个简单的替代方法是先匹配foo
字符串,然后找到第一次出现的索引。然后搜索bar
,看看是否能找到出现在该索引之前的出现。
如果您想查找前面bar
没有直接foo
包含 的实例,我也可以为此提供一个正则表达式(不使用后视),但它会非常丑陋。基本上,反转 的意义/foo/
——即/[^f]oo|[^o]o|[^o]|$/
。
解决方案 5:
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))
>>>
来源。
扫码咨询,免费领取项目管理大礼包!