regex 如何使正则表达式负前瞻停止?

o2rvlv0m  于 2023-03-04  发布在  其他
关注(0)|答案(3)|浏览(111)

我想匹配具有以下条件的字符串

  • 必须以A开头
  • 后面跟着任何计数,除非是两个连续的大写字母
  • 后跟一个数字(应捕获)

A bcd 1应匹配并捕获1
Abcd1应匹配并捕获1
A bcd不应匹配,因为没有数字
A BCd 1不应匹配,因为在A和数字之间有大写的C
A bcd 1 EF应该匹配,因为1EF之前
我想出了

A(?!.*[A-Z]{2})+?.*(\d+)

但这对最后一个用例不起作用,因为负向前看超出了1
这里是Playground

bwntbbo3

bwntbbo31#

请注意,(?!.*[A-Z]{2})+?(?!.*[A-Z]{2})相同,因为只需要执行一次前瞻(+?匹配一个或多个但尽可能少的出现,量化后向查找总是错误的想法)。.*尽可能多地匹配除换行符之外的任何字符,因此它将获取直到最后一个数字的所有文本,并且(\d+)因此捕获匹配行上的最后一个数字。
您可以使用

A(?:(?![A-Z]{2}).)*?(\d+)

请参见regex demo

  • 详细信息 *:
  • A-一个A字母
  • (?:(?![A-Z]{2}).)*?-除换行符以外的字符(不以两个大写字母的字符序列开头)出现零次或多次(但尽可能少)
  • (\d+)-第1组:一个或多个数字。

如果需要跨多行匹配,请参阅How do I match any character across multiple lines in a regular expression?中的解决方案

li9yvcax

li9yvcax2#

您可以使用\D排除lookahead和match中的匹配数字

A(?!\D*[A-Z]{2})\D*(\d+)

参见regex101 demo
为了不跨换行符,可以使用[^\d\n]
如果还希望防止A成为部分单词匹配的一部分,则可以附加单词边界\bA

\bA(?![^\d\n]*[A-Z]{2})[^\d\n]*(\d+)

参见另一个regex101 demo

cvxl0en2

cvxl0en23#

除了捕获数字,还可以使用\K在遇到数字时重置匹配,这样数字就可以完全匹配:

^A(?:(?![A-Z]{2}).).*?\K\d+

演示:https://regex101.com/r/JvrSIR/1

相关问题