【问题标题】:why regexp doesn't match?为什么正则表达式不匹配?
【发布时间】:2022-01-04 14:45:03
【问题描述】:

下面是一个匹配数字的模式。它几乎可以工作。第二行应该和99匹配但是没有匹配?为什么?

(?<!\d[- ]|[\d.,])\(?-?(?:(?:[1-9]\d{0,2}(?:(?:[. ]\d{3})*|\d*))|0)(?:\b|[,]\d{1,3})-?\)?(?![\d.,\/]|-[\d\/])


100,00stk => 100,00
99stk => 99 \\ this is not matched
10,45stk => 10,45

https://regex101.com/r/nwRCKo/1

【问题讨论】:

  • 这是由于(?:\b|,\d{1,3})中的单词边界,请参阅regex101.com/r/nwRCKo/2,如果删除它会得到匹配。但是,该模式过于模糊,即使在此修复之后也可能无法正常工作。
  • @WiktorStribiżew 在我删除 `\b|´ 后它仍然不起作用
  • 确实如此 - regex101.com/r/nwRCKo/2
  • @WiktorStribiżew 创建一个答案 :)
  • 好的,但我相信(?![\d.,\/]|-[\d\/]) 并不适合您。至少在删除\b 之后,它会在很多情况下停止工作。模式应该是固定的,但我对它没有要求。

标签: php regex


【解决方案1】:

这里的主要问题是单词边界的使用,但解决问题并不那么明显。

关于你所拥有的正则表达式的要点是它匹配某些特定上下文中的一些数字,并且两边的环视都意味着匹配失败,所以你根本不会得到匹配。如果您在可选的 ) 字符后放置一个否定的前瞻,正则表达式引擎可能会回溯,您仍然会得到这个匹配。删除单词边界后,您需要在此处防止任何回溯。

因此,将 (?:\b|[,]\d{1,3}) 替换为 (?:[,]\d{1,3})? 并通过应用所有格量词使所有后续可选模式成为原子:

(?<!\d[- ]|[\d.,])\(?-?(?:(?:[1-9]\d{0,2}(?:(?:[. ]\d{3})*|\d*))|0)(?:,\d{1,3})?+-?+\)?+(?![\d.,\/]|-[\d\/])

见this regex demo。

【讨论】:

  • 负前瞻前的最后一个?+。需要+ 吗?前面的) 实际上不是一个组,而是一个实际的),因为它前面有一个转义字符
  • 在模式的开头,就在负后视后面有两个可选字符\(?-?。他们是否也应该拥有+?
  • @clarkk 通常不需要。回溯限制可能很好回溯,如果有数字、.、, 或带有空格/- 的数字,您希望任何匹配失败。 ?+ 在 PCRE 中很好,它意味着“可选地匹配一次出现并且永不返回”。因此,如果 \)?+ 匹配 ) 字符,它将永远不会被重试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-24
  • 2017-03-21
  • 2017-08-22
  • 2021-01-24
  • 2014-05-21
相关资源
最近更新 更多