为什么这个正则表达式在Python中工作,而在Ruby中不起作用:
/(?<!([0-1b][0-9]|[2][0-3]))/
很高兴听到解释以及如何在 Ruby 中绕过它
使用整行代码进行编辑:
re.sub(r'(?<!([0-1b][0-9]|[2][0-3])):(?!([0-5][0-9])((?i)(am)|(pm)|(a.m)|(p.m)|(a.m.)|(p.m.))?b)' , ':n' , s)
基本上,我试图在有冒号时添加'n'
,这不是时间。
Ruby 正则表达式引擎不允许在后面捕获组。 如果需要分组,可以使用非捕获组(?:)
:
[8] pry(main)> /(?<!(:?[0-1b][0-9]|[2][0-3]))/
SyntaxError: (eval):2: invalid pattern in look-behind: /(?<!(:?[0-1b][0-9]|[2][0-3]))/
[8] pry(main)> /(?<!(?:[0-1b][0-9]|[2][0-3]))/
=> /(?<!(?:[0-1b][0-9]|[2][0-3]))/
文档:
(?<!subexp) negative look-behind
Subexp of look-behind must be fixed-width.
But top-level alternatives can be of various lengths.
ex. (?<=a|bc) is OK. (?<=aaa(?:b|cd)) is not allowed.
In negative look-behind, capturing group isn't allowed,
but non-capturing group (?:) is allowed.
从这个答案中学到了。
根据Onigmo 正则表达式文档,在负面回溯中不支持捕获组。尽管这在正则表达式引擎中很常见,但并非所有引擎都将其视为错误,因此您可以在re
和 Onigmo 正则表达式库中看到差异。
现在,至于你的正则表达式,它在 Ruby 和 Python 中都无法正常工作:Python 和 Ruby 正则表达式中字符类内的b
匹配 BACKSPACE (x08
) 字符,而不是单词边界。此外,当您在可选的非单词字符之后使用单词边界时,如果该字符出现在字符串中,则单词字符必须立即出现在该非单词字符的右侧。单词边界必须移动到.?
之前的m
之后的右边。
当前方法的另一个缺陷是,回溯并不是排除某些上下文的最佳方法,如下所示。 例如,您无法解释时间数字和am
/pm
之间的可变空格量。最好匹配您不想触摸的上下文,匹配并捕获要修改的上下文。因此,我们在这里需要两个主要的替代方案,一个在时间字符串中匹配am
/pm
,另一个在所有其他上下文中匹配它们。
您的模式还有太多可以使用字符类和?
量词合并的替代项。
正则表达式演示
b((?:[01]?[0-9]|2[0-3]):[0-5][0-9]s*[pa].?mb.?)
:b
- 字界((?:[01]?[0-9]|2[0-3]):[0-5][0-9]s*[pa].?mb.?)
- 捕获组 1:(?:[01]?[0-9]|2[0-3])
- 可选的0
或1
,然后是任何数字或2
,然后是0
到3
的数字:[0-5][0-9]
-:
,然后是00
到59
的数字s*
- 0+ 空格[pa].?mb.?
-a
或p
、可选点、m
、字边界、可选点
|
- 或m
、字边界、可选点
b[ap].?mb.?
- 字边界、a
或p
、可选点、蟒蛇固定解决方案:
import re
text = 'am pm P.M. 10:56pm 10:43 a.m.'
rx = r'b((?:[01]?[0-9]|2[0-3]):[0-5][0-9]s*[pa].?mb.?)|b[ap].?mb.?'
result = re.sub(rx, lambda x: x.group(1) if x.group(1) else "n", text, flags=re.I)
红宝石解决方案:
text = 'am pm P.M. 10:56pm 10:43 a.m.'
rx = /b((?:[01]?[0-9]|2[0-3]):[0-5][0-9]s*[pa].?mb.?)|b[ap].?mb.?/i
result = text.gsub(rx) { $1 || "n" }
输出:
"n n n 10:56pm 10:43 a.m."
当然,@mrzasa发现了问题所在。
但。。 猜测您打算用":"替换非时间冒号的意图,
我想可以这样做。也做一点空白修剪。
(?i)(?<!b[01][0-9])(?<!b[2][0-3])([^Srn]*:)[^Srn]*(?![0-5][0-9](?:[ap].?mb.?)?)
PCRE - https://regex101.com/r/7TxbAJ/1 更换$1n
蟒蛇 - https://regex101.com/r/w0oqdZ/1 替换1n
可读版本
(?i)
(?<!
b [01] [0-9]
)
(?<!
b [2] [0-3]
)
( # (1 start)
[^Srn]*
:
) # (1 end)
[^Srn]*
(?!
[0-5] [0-9]
(?: [ap] .? m b .? )?
)