Ruby 正则表达式使用负向前瞻以逗号分隔唯一数字

问题描述 投票:0回答:1

以下是一个正则表达式,它匹配以逗号分隔的数字列表,并且仅允许输入唯一的数字:

^(?!.*\b(\d+)\b.*\b\1\b)(\d)(,(\d))*$

例如,它允许 1,2,3,但不允许 1,1 或 2,1,1。

有人可以用简单的语言解释一下它是如何工作的吗?

令我困惑的是否定的前瞻断言。在网络上可用的解释中,它显示的语法如下

语法为:X(?!Y),意思是“搜索X,但前提是后面不跟Y”。

参考:https://javascript.info/regexp-lookahead-lookbehind#negative-lookahead

但在我显示的正则表达式中,它不遵循上述语法。那么它是如何工作的呢?

当匹配1,2,3时会发生什么匹配过程?

当不匹配2,1,1时,会发生什么匹配过程?

当 1,2,3 或 2,1,1 匹配时,它们首先匹配正则表达式

(\d)(,(\d))*
的部分,然后针对负向前看部分
(?!.*\b(\d+)\b.*\b\1\b)
断言其匹配结果,或者首先运行负向前看部分然后剩下的部分?

此外,如果我在负向先行部分的

.*
之前和之后删除
\b
,那么它也会开始匹配 1,1 或 2,1,1。那么负向前看部分中删除的
.*
有什么意义呢?

注意:我想在 Ruby 代码中使用正则表达式,以防需要通知。

正则表达式的源参考是

https://stackoverflow.com/a/45946721/936494

https://stackoverflow.com/a/45944821/936494

谢谢。

regex ruby regex-lookarounds
1个回答
0
投票

消极前瞻

(?!.*\b(\d+)\b.*\b\1\b)

在字符串开头锚点 (

^
) 之后断言,“情况并非如此 (
(?!...)
),在跳过零个或多个字符(行终止符除外)(
.*
) 后,存在由一个或多个数字 (
\d+
) 组成的字符串,保存到捕获组 1 (
(\d+)
),前面和后面是单词边界 (
\b
),后面是一个或多个字符 (行终止符除外)(
.*
),后跟捕获组 1 (
\1
) 的内容,前后是字边界”。

因此,对于字符串

'a 12, *34 *12'
,负向先行失败(因为
'12'
前后有单词边界,重复),而对于字符串
'a 12, *34 512'
则成功(尽管
'12'
重复,但第二个
'12'
前面没有单词边界)。如果先行失败,则不会有匹配项,因此不会评估正则表达式的其余部分。如果成功,正则表达式引擎将继续评估正则表达式的其余部分。

由于正则表达式以字符串开头锚点 (

^
) 开头,如果满足前瞻,则不会将正则表达式的字符串指针从字符串的开头移动,在这种情况下,正则表达式实际上变为

^(\d)(,(\d))*$

这满足,例如,

'1,2,3'
'1'
将被保存到捕获组 2(捕获组 1 用于前瞻),
',2'
将被保存到捕获组 3,
'2'
将被保存到捕获组 4,
',3'
将被保存到捕获组 3(覆盖
',2'
)和
'3'
将保存到捕获组 4(覆盖
'2'
)。 演示

鉴于正则表达式中紧随负前瞻的部分,我们发现负前瞻可以按如下方式收紧1

^(?!(?:\d,)*(\d),(?:\d,)*\1(?=,|\z))(\d)(,(\d))*$

演示

1。我在链接处使用了正向前瞻

(?=,|$)
(而不是
(?=,|\z)
),以便针对多个字符串测试正则表达式。

© www.soinside.com 2019 - 2024. All rights reserved.