java - X?正则表达式量词无法按预期工作(我)

标签 java regex

输入字符串:

  • aaa---foo---ccc---ddd
  • aaa---bar---ccc---ddd
  • aaa---------ccc---ddd

正则表达式:aaa.*(foo|bar)?.*ccc.*(ddd)

此正则表达式在任何情况下都找不到第一组 (foo|bar)。对于捕获组 1,它始终返回 null。 我的问题是为什么以及如何避免这种情况。

这是我的正则表达式的非常简单的示例,仅用于演示。如果我删除 ? 量词,但输入字符串可以根本没有这个组(aaa--------ccc---ddd)并且我仍然需要确定它是foo还是bar还是null。但组 1 始终为 null

包含此正则表达式和测试字符串的页面:http://fiddle.re/45c766

最佳答案

这就是它不起作用的原因:当模式中有 .* 时,匹配器的算法将尝试匹配尽可能多的字符,以使模式的其余部分正常工作。在这种情况下,如果它尝试从字符串的整个剩余部分作为 .* 开始并删除一个字符直到匹配,它会发现 (对于 "aaa---foo--- ccc---ddd") 可以让 .* 匹配 9 个字符;那么 (foo|bar)? 不匹配任何内容,这是可以的,因为它是可选的;接下来的 .* 匹配 0 个字符,然后模式的其余部分匹配。所以这就是它选择的那个。

.*更改为.*的原因?:

aaa.*?(foo|bar)?.*?ccc.*(ddd)   

不起作用的是匹配器反向执行相同的操作。它从 0 个字符匹配开始,然后确定是否可以使该模式起作用。当它尝试这样做时,它会发现它可以使 .*? 匹配 0 个字符;那么 (foo|bar)? 不匹配任何内容;那么第二个 .*? 匹配 9 个字符;那么模式的其余部分匹配ccc---ddd。所以无论哪种方式,它都不会达到您想要的效果。

答案中有几个解决方案,都涉及前瞻。这是另一个解决方案:

aaa.*(foo|bar).*ccc.*(ddd)|aaa.*ccc.*(ddd)

这基本上按顺序检查两种模式;首先,它检查是否存在包含 foo|bar 的模式,如果不匹配,它将搜索另一种不包含 foo|bar 的可能性>。如果 foo|bar 存在的话,它总是会找到它。

不过,所有这些解决方案都涉及相当难以阅读的正则表达式。这就是我的编码方式:

Pattern pat1 = Pattern.compile("aaa(.*)ccc.*ddd");
Pattern pat2 = Pattern.compile("foo|bar");

Matcher m1 = pat1.matcher(source);
String foobar;
if (m1.matches()) {
    Matcher m2 = pat2.matcher(m1.group(1));
    if (m2.find()) {
        foobar = m2.group(0);
    } else {
        foobar = null;
    }
}

通常,尝试使用一个出色的正则表达式来解决问题会导致代码可读性较差(并且可能效率较低),而不仅仅是将问题分解为多个部分。

关于java - X?正则表达式量词无法按预期工作(我),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26346330/

相关文章:

javascript - 如何使用 javascript/jquery 从字符串中删除文本?

javascript - 如何就地反转字符串中的所有单词也会反转这些单词在字符串中的位置,同时将标点符号保留在原来的位置

python - 从停用词列表中重新替换多个字符串模式

javascript - 使用正则表达式 (regex) 替换 jQuery/JavaScript 中的选定文本

java - 为什么我的程序中存储的值总是被删除

java - Android 4.0.3 进度对话框关闭

java - 在Java中将字符串数组转换为字符串

java - jackson 的 Access.WRITE_ONLY 在测试期间为空

java - JAXB 继承冲突 - 在子类上重新注释

java - 匹配器: "No match found..."