是否可以匹配逗号分隔的十进制整数列表,其中列表中的整数总是递增1?
这些应匹配:
0,1,2,3
8,9,10,11
1999,2000,2001
99,100,101
这些不匹配(完整 - 最后两个具有匹配的子序列):
42
3,2,1
1,2,4
10,11,13
答案 0 :(得分:21)
是的,当使用支持反向引用和条件的正则表达式引擎时,这是可能的。
首先,连续数字列表可以分解为每对数字连续的列表:
(?=(?&cons))\d+
(?:,(?=(?&cons))\d+)*
,\d+
此处(?=(?&cons))
是谓词的占位符,可确保两个数字是连续的。该谓词可能如下所示:
(?<cons>\b(?:
(?<x>\d*)
(?:(?<a0>0)|(?<a1>1)|(?<a2>2)|(?<a3>3)|(?<a4>4)
|(?<a5>5)|(?<a6>6)|(?<a7>7)|(?<a8>8))
(?:9(?= 9*,\g{x}\d (?<y>\g{y}?+ 0)))*
,\g{x}
(?(a0)1)(?(a1)2)(?(a2)3)(?(a3)4)(?(a4)5)
(?(a5)6)(?(a6)7)(?(a7)8)(?(a8)9)
(?(y)\g{y})
# handle the 999 => 1000 case separately
| (?:9(?= 9*,1 (?<z>\g{z}?+ 0)))+
,1\g{z}
)\b)
有关简要说明,处理999,1000
类型对的第二个案例更容易理解 - 在this answer concerned with matching a^n b^n中有一个非常详细的说明。两者之间的联系是,在这种情况下,我们需要匹配9^n ,1 0^n
。
第一种情况稍微复杂一些。它的最大部分处理递增十进制数字的简单情况,由于所述数字的数量而相对冗长:
(?:(?<a0>0)|(?<a1>1)|(?<a2>2)|(?<a3>3)|(?<a4>4)
|(?<a5>5)|(?<a6>6)|(?<a7>7)|(?<a8>8))
(?(a0)1)(?(a1)2)(?(a2)3)(?(a3)4)(?(a4)5)
(?(a5)6)(?(a6)7)(?(a7)8)(?(a8)9)
第一个块将捕获数字是否为N到组aN,然后第二个块将使用条件来检查使用了哪些组。如果组aN非空,则下一个数字应为N + 1。
第一个案例的其余部分处理像1999,2000
这样的案例。这再次落入模式N 9^n, N+1 0^n
,因此这是匹配a^n b^n
和递增十进制数字的方法的组合。 1,2
的简单情况作为极限情况处理,其中n = 0。
完整的正则表达式:https://regex101.com/r/zG4zV0/1
或者,如果支持递归子模式引用,则可以稍微更直接地实现(?&cons)
谓词:
(?<cons>\b(?:
(?<x>\d*)
(?:(?<a0>0)|(?<a1>1)|(?<a2>2)|(?<a3>3)|(?<a4>4)
|(?<a5>5)|(?<a6>6)|(?<a7>7)|(?<a8>8))
(?<y>
,\g{x}
(?(a0)1)(?(a1)2)(?(a2)3)(?(a3)4)(?(a4)5)
(?(a5)6)(?(a6)7)(?(a7)8)(?(a8)9)
| 9 (?&y) 0
)
# handle the 999 => 1000 case separately
| (?<z> 9,10 | 9(?&z)0 )
)\b)
在这种情况下,两个语法9^n ,1 0^n
,n&gt; = 1和prefix N 9^n , prefix N+1 0^n
,n&gt; = 0几乎都是明确写出来的。
完成替代正则表达式:https://regex101.com/r/zG4zV0/3