正则表达式匹配两组重复数字,其中两个都不允许是相同的数字

时间:2015-09-29 11:20:49

标签: regex negative-lookahead

民间,   我正在尝试使用正则表达式来处理大量的数字字符串,并匹配特定模式的数字序列,其中一些数字在组中重复。部分要求是确保给定模式的各部分之间的唯一性。

我想要实现的匹配类型的一个例子

ABBBCCDD 

将其解释为一组数字。但A,B,C,D不能相同。每个重复都是我们试图匹配的模式。

我一直在使用带有负面预测的正则表达式作为此匹配的一部分,它可以工作,但不是所有时间,我很困惑为什么。我希望有人可以解释为什么会出现故障并提出解决方案。

因此,为了解决ABBBCCDD问题,我使用群组负面预测来提出这个RE ..

(.)(?!\1{1,7})(.)\2{2}(?!\2{1,4})(.)\3{1}(?!\3{1,2})(.)\4{1}

要打破这个......

(.)           single character wildcard group 1 (A)
(?!\1{1,7})   negative look-ahead for 1-7 occurrences of group 1 (A)
(.)           single character wildcard group 2 (B)
\2{2}         A further two occurrences of group 2 (B)
(?!\2{1,4})   Negative look-ahead of 1-4 occurrences of group 2 (B)
(.)           single character wildcard group 3 (C)
\3{1}         One more occurrence of group 3 (C)
(?!\3{1,2})   Negative look-ahead of 1-2 occurrences of group 3 (C)
(.)           single character wildcard group 4 (D)
\4{1}         one more occurrence of group 4 (D)

这里的想法是,负面预测可以作为验证某个特定字符在意外情况下未找到的方法。所以在接下来的7个字符中检查A.一旦B和它的2次重复匹配,我们就会在接下来的4个字符中向前看待B。最后,一旦这对Cs匹配,我们会在最后的2中查找C作为检测不匹配的方法。

对于测试数据,此字符串“01110033”与表达式匹配。但它不应该因为A的'0'在C位置重复。

我在Python中运行了这个表达式的检查,并在PCRE模式下运行了grep(-P)。两者都匹配错误的模式。

我将表达式放在https://regex101.com/中,并带有相同的测试字符串“01110033”,它也匹配在那里。我没有足够的评分来发布我尝试过的测试数据的图像。所以这里有一些来自grep -P

的命令行运行的文本抓取

因此我们在CC位置重复A的无效表达式通过..

$ echo "01110033" | grep -P '(.)(?!\1{1,7})(.)\2{2}(?!\2{1,4})(.)\3{1}(?!\3{1,2})(.)\4{1}'
01110033
$

将DD更改为11,复制BBB,我们也发现尽管B进行了前向否定检查,但仍然可以通过..

$ echo "01110011" | grep -P '(.)(?!\1{1,7})(.)\2{2}(?!\2{1,4})(.)\3{1}(?!\3{1,2})(.)\4{1}'
01110011
$

现在将DD更改为“00”,将CC数字复制到低位并看到它不匹配..

$ echo "01110000" | grep -P '(.)(?!\1{1,7})(.)\2{2}(?!\2{1,4})(.)\3{1}(?!\3{1,2})(.)\4{1}'
$

从表达式中删除CC“(?!\ 3 {1,2})”的前向 - 否定检查,我们重复D位置的C位使其通过。

$ echo "01110000" | grep -P '(.)(?!\1{1,7})(.)\2{2}(?!\2{1,4})(.)\3{1}(.)\4{1}'
01110000
$

返回原始测试编号并将CC数字切换为与B中相同的“1”使用。它无法通过。

$ echo "01111133" | grep -P '(.)(?!\1{1,7})(.)\2{2}(?!\2{1,4})(.)\3{1}(?!\3{1,2})(.)\4{1}'
$

要为BBB组播放,请将B数字设置为与A遇到的相同的0。也无法匹配..

$ echo "00002233" | grep -P '(.)(?!\1{1,7})(.)\2{2}(?!\2{1,4})(.)\3{1}(?!\3{1,2})(.)\4{1}'
$ 

然后取出A的负面预测,我们可以匹配..

$ echo "00002233" | grep -P '(.)(.)\2{2}(?!\2{1,4})(.)\3{1}(?!\3{1,2})(.)\4{1}'
00002233
$ 

所以在我看来,前向否定检查是有效的,但它只适用于下一个相邻的一组,或者它的预期前瞻范围在某种形式下被缩短,可能是我们试图匹配的额外事物。

如果我在B之后在A上添加了一个额外的前瞻并且它的重复已被处理,我们得到它以避免在重复使用A数字的CC部分上匹配..

$ echo "01110033" | grep -P '(.)(?!\1{1,7})(.)\2{2}(?!\1{1,4})(?!\2{1,4})(.)\3{1}(?!\3{1,2})(.)\4{1}'
$

为了更进一步,然后在匹配CC集之后,我需要再次重复A和B的负向前瞻。这似乎是错的。

希望RE专家可以澄清我在这里做错了什么,或者根据我观察的内容确认负向前瞻是否确实有限

4 个答案:

答案 0 :(得分:0)

(.)(?!.{0,6}\1)(.)\2{2}(?!\2{1,4})(.)\3{1}(?!\3{1,2})(.)\4{1}

   ^^^^^^^^

lookahead出现在字符串中的任何位置时,将\1更改为禁止匹配。请参阅演示。您也可以在正则表达式中修改其他部分。

https://regex101.com/r/vV1wW6/31

答案 1 :(得分:0)

注意:已更新。

正如vks已经指出的那样,你的负面前瞻并不排除你的想法 - 例如\1{1,7}只会排除A,AA,AAA,AAAA,AAAAA,AAAAAA和AAAAAAA。我认为您希望前瞻为.*\1.*\2.*\3等。

但是,这是另一个想法:预先过滤任何具有非相邻重复字符的行很容易:

grep -P -v '(.)(?!\1).*\1'

然后你对结果的正则表达式更加简单:.{1}.{3}.{2}.{2}

事实上,整个事情可以使用第一个作为负前期预测约束来组合:

(?!.*(.)(?!\1).*\1).{1}.{3}.{2}.{2}

或者如果你需要像原来那样捕捉数字:

(?!.*(.)(?!\1).*\1)(.){1}(.){3}(.){2}(.){2}

但请注意,这些数字现在为\ 2 \ 3 \ 4 \ 5,因为\ 1位于前瞻中。

答案 2 :(得分:0)

基于到目前为止的反馈,我给出了另一个答案,它不依赖于基于总长度的算术,并且将自包含地识别长度序列1,3中的4个唯一字符/数字组的任何序列,2,2在字符串中的任何地方:

/(?<=^|(.)(?!\1))(.)\2{0}(?!\2)(.)\3{2}(?!\2|\3)(.)\4{1}(?!\2|\3|\4)(.)\5{1}(?!\5)/gm
 ^^^^^^^^^^^^^^^^ this is a look-behind that makes sure we're starting with a new character/digit
                 ^^^^^^^^ this is the size-1 group; yes the \2{0} is superfluous
                         ^^^^^^ this ensures the next group is unique
                               ^^^^^^^^ this is the size-3 group
etc.

如果这更接近您的解决方案,请告诉我。如果是这样,并且如果所有“模式”都包含您正在寻找的组大小的序列(如1,3,2,2),我可以提出一些代码,为任何此类代码生成相应的正则表达式输入“模式”。

答案 3 :(得分:0)

这里有一些关于最终解决方案对我来说是什么样的细节..

所以从根本上来说(?!\ 1 {1,7})并不是我想象的那样,而是我遇到的问题的全部原因。真诚地感谢你们为我找到这个问题。

我所展示的例子是大约50个,我必须从一组模式中制定出来。

最终成为..

ABBBCCDD
09(.)(?!.{0,6}\1)(.)\2{2}(?!.{0,3}\2)(.)\3{1}(?!.{0,1}\3)(.)\4{1}

所以一旦\ 1(A)被捕获,我测试了在A之前的0-6个野生动物的负向前瞻。然后我捕获\ 2(B),它的两次重复然后给予B负0a野生+ B的预测等等。

它使焦点集中在消极地向前看,以确保被抓住的群体不会重复他们不应该重复的地方。然后,随后的捕获及其重复模式将完成剩下的工作以确保匹配。

最终集中的其他示例:

ABCCDDDD
(.)(?!.{0,6}\1)(.)(?!.{0,5}\2)(.)\3{1}(?!.{0,3}\3)(.)\4{3}

AABBCCDD
(.)\1{1}(?!.{0,5}\1)(.)\2{1}(?!.{0,3}\2)(.)\3{1}(?!.{0,1}\3)(.)\4{1}

ABCCDEDE
09(.)(?!.{0,6}\1)(.)(?!.{0,5}\2)(.)\3{1}(?!.{0,3}\3)(.)(?!\4{1})(.)\4{1}\5{1}