Java 8 正则表达式:模式中的一个捕获组不匹配,但整个模式确实匹配

3

这是我的第一个问题。很高兴与大家见面。

我在Java 8中创建了以下正则表达式模式(这只是我实际代码的简化示例,为了清晰起见):

(?<!a)([0-9])\,([0-9])(?!a)|(?<!b)([0-9]) ([0-9])(?!b)|(?<!c)([0-9])([0-9])(?!c)

一般来说,这包括三种选择: 第一种匹配由逗号分隔的两个单个数字,例如:

1,1
2,0
4,5

第二个正则表达式匹配以空格分隔的两个单个数字,例如:

1 1
2 0
4 5

第三个模式匹配了两个连续的单个数字,例如:
11
20
45

每个替代方案都使用了“lookaround”,它们的内容必须略有不同 - 这就是为什么我不能把所有东西都放在一起的原因:
([0-9])[, ]?([0-9])

每个匹配的数字都被包含在一个捕获组中,现在我有了第二行来“呼叫”这些捕获的数字,如下所示:

(?<!n)($1 $2|$3 $4|$5 $6)(?!n)

所以,最终我需要匹配一个文本,其中的数字用单个空格分隔,且不被'n'包围。因此,如果上面任何一个示例都符合第1行的模式,则第2行的模式应该匹配这些内容:
1 1
2 0
4 5
11 11
22 00
44 55 

而不是这些:

n1 1
2,0
45
asd asd asd

问题如下:即使在被测试的文本中没有这些捕获的数字,它也会返回匹配项,但我确实有空格... 所以在这里我没有得到匹配,这是正确的:
aaaaaaaaa
bbbbbbbbb
aasdfasdf

但是这里我得到以下匹配项(最明显的原因是有一个或多个空格):

abc abc
q w r t y
as df

请问有人知道这种情况是否正常,即使捕获组中的字符没有被第一行捕获,'非捕获组'部分(一个空格)仍会匹配,因此整个模式返回匹配,就好像如果第一行未捕获任何内容,则捕获组可以是零长度匹配的第二行?感谢您对此的任何评论。


我认为这个简化的正则表达式没有问题(除了它是一个正则表达式,而且相当复杂 :))。也许编码的正则表达式中有错别字,如果你想要答案,请展示出来。但最好使用String.split和maybe Integer.parseInt或者其他简单易读的方法来解决你的任务。否则,你将会解决两个任务。 - Yury Nevinitsin
1
你是否可能混淆了“捕获组”(“括号”)和“环视”?... (?<!a), (?<!b), (?<!c)应该做什么/匹配什么? - xerx593
我有第二行代码来像这样“呼叫”这些捕获的数字:”我不理解这部分。 “呼叫”是什么意思?代码中有$1,$2等表示替换字符串,但它还具有后顾和先顾,这对替换字符串没有任何影响。 - VGR
你是否尝试使用反向引用或替换?请提供一个 [mcve]。 - shmosel
感谢您的评论!以下是一些澄清说明:@VGR 这是用于检查翻译的软件代码:在第一行/字段中,我输入将匹配源(原始)文本的正则表达式模式,在第二行/字段中,我输入将匹配目标(翻译)文本的正则表达式模式。我可以在其中一行中使用反向引用来“调用”在另一行中捕获的内容。这就是为什么我在两行中都有lookaround,它们确保在源文本中匹配的内容不被'a'、'b'或'c'所包围,而在目标文本中匹配的内容也不被'n'所包围。 - Kacper
显示剩余7条评论
1个回答

1
您的正则表达式匹配了空格,因为1,1字符串的结果模式是(?<!n)(1 1| | )(?!n),它可以匹配既不前置也不后置空格的空格。
当替换反向引用在.replaceAll/.replaceFirst中没有匹配到任何字符串时,它被赋予一个空字符串(在使用.find() / .matches()时,它被赋予null),因此您仍然会得到结果模式中的空白备选项。
您可以利用这个功能以及每个备选项都有两个捕获组的事实,通过在字符串替换模式中连接替换反向引用来摆脱备选项。

搜索: (?<!a)([0-9]),([0-9])(?!a)|(?<!b)([0-9]) ([0-9])(?!b)|(?<!c)([0-9])([0-9])(?!c)
替换: (?<!n)($1 $2|$3 $4|$5 $6)(?!n)

请注意如何连接反向引用: 所有对奇数组的引用都在前面,然后将所有对偶数组的引用放置在没有备选项的模式中。

请参见正则表达式演示

请注意,即使跨备选项的组数不同,您也可以向每个组添加“虚拟”空组,这种方法仍然有效。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接