如何使捕获组可选?

时间:2018-05-28 06:41:07

标签: java regex

输入

example("This is tes't")

example('This is the tes\"t')

输出

This is tes't

This is the tes"t

代码

 String text = "example(\"This is tes't\")";
//String text = "$.i18nMessage('This is the tes\"t\')";
final String quoteRegex = "example.*?(\".*?\")?('.*?')?";
        Matcher matcher0 = Pattern.compile(quoteRegex).matcher(text);
        while (matcher0.find()) {
            System.out.println(matcher0.group(1));
            System.out.println(matcher0.group(2));

        }

我看到输出为

null
null

虽然当我使用正则表达式example.*?(\".*?\")时,它会返回This is tes't,当我使用example.*?('.*?')时,它会返回 This is the tes"t但是当我将它们与example.*?(\".*?\")?('.*?')?结合使用时,它返回null。为什么?

1 个答案:

答案 0 :(得分:2)

正则表达式末尾的.*?(\".*?\")?('.*?')?子模式序列可以匹配空字符串(所有3个部分都使用匹配0个或更多字符的* / *?进行量化)。在匹配example之后,首先跳过.*?,并且仅在后续子模式不匹配时展开。但是,它们都匹配(之前的空字符串,因此,example中只有matcher0.group(0)

使用使第1组成为强制性的替换(demo):

Pattern.compile("example.*?(\".*?\"|'.*?')"

或者带有驯化贪婪令牌(demo)的变体,可以摆脱交替:

Pattern.compile("example.*?(([\"'])(?:(?!\\2).)*\\2)"

或者,更好的是,支持转义序列(another demo):

Pattern.compile("example.*?(\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\"|'[^'\\\\]*(?:\\\\.[^'\\\\]*)*')"

在所有3个示例中,您只需要访问第1组。如果(example"之间只能',则应替换{{ 1}} .*?,因为它会使匹配更安全。虽然,使用正则表达式匹配字符串文字(至少使用一个正则表达式)永远不会太安全。