后视中的模式无效



为什么这个正则表达式在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])- 可选的01,然后是任何数字或2,然后是03的数字
      • :[0-5][0-9]-:,然后是0059
      • 的数字
      • s*- 0+ 空格
      • [pa].?mb.?-ap、可选点、m字边界、可选点
  • |- 或
  • b[ap].?mb.?- 字边界、ap、可选点、
  • m字边界、可选点

蟒蛇固定解决方案:

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 .? )?
)

最新更新