在字符类(“ []”)中的元字符

时间:2019-07-31 15:08:12

标签: java regex pattern-matching

我对Java Regex的理解是这样。有两套元字符:

  • 用在字符类之外的正则表达式中([]内):<([{\\^-=$!|]})?*+.>
  • 在字符类中使用:\][-&^

如果我们希望某个字符(例如连字符-)在字符类中按字面意义进行匹配,则必须用反斜杠(\)对其进行转义。

Java Doc

中的以下描述支持此视图
  

字符类   角色类别可能出现在其他角色中   类,并且可以由联合运算符(隐式)和   相交运算符(&&)。联合运算符表示一个类   包含至少一个操作数中的每个字符   类。相交运算符表示一个包含每个   这两个操作数类中的字符。

     

字符类运算符的优先级如下   最高到最低:

     
      
  1. 文字逃逸\ x
  2.   
  3. 分组[...]
  4.   
  5. 范围
  6.   
  7. 联盟[a-e] [i-u]
  8.   
  9. 交叉点[a-z && [aeiou]]
  10.   
     

请注意   字符类中有效地使用了不同的元字符集   而不是角色类之外。

这是正确的理解吗?

令我惊讶的是,除了使用反斜杠之外,我们还可以使用java.util.regex.Pattern.quote()来逃脱字符类中的第二个字符集。我认为该方法仅适用于第一组元字符。

测试程序

以下测试程序说明Pattern.quote()\(以及\Q\E)都可以在字符类中用引号引起来:

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;

import java.util.regex.Pattern;

public class RegexTest {
    @Rule
    public TestName testName = new TestName();

    @Test
    public void testHyphenCharClassByPatternQuote() {
        String regex = "[" + Pattern.quote("-") + "]";
        Pattern p = Pattern.compile(regex);
        String[] tests = {
            "-"
            , "a"
        };
        for (String test : tests) {
            System.out.println(testName.getMethodName() + " matching " + test + ":" + p.matcher(test).matches());
        }
    }

    @Test
    public void testHyphenCharClassByBackSlash() {
        String regex = "[\\-]";
        Pattern p = Pattern.compile(regex);
        String[] tests = {
            "-"
            , "a"
        };
        for (String test : tests) {
            System.out.println(testName.getMethodName() + " matching " + test + ":" + p.matcher(test).matches());
        }
    }

    @Test
    public void testHyphenCharClassByQE() {
        String regex = "[\\Q-\\E]";
        Pattern p = Pattern.compile(regex);
        String[] tests = {
            "-"
            , "a"
        };
        for (String test : tests) {
            System.out.println(testName.getMethodName() + " matching " + test + ":" + p.matcher(test).matches());
        }
    }

}

测试输出

testHyphenCharClassByQE matching -:true
testHyphenCharClassByQE matching a:false
testHyphenCharClassByBackSlash matching -:true
testHyphenCharClassByBackSlash matching a:false
testHyphenCharClassByPatternQuote matching -:true
testHyphenCharClassByPatternQuote matching a:false

2 个答案:

答案 0 :(得分:1)

您基本上是正确的,但是pattern.quote()方法可以正常工作。似乎使您感到困惑的是字符类范围内连字符的性质。

Pattern class doc报价下列出了以下转义修饰符  部分:

  

\没什么,但引用了以下字符
  \Q一无所有,但引用所有字符,直到\E
  \E一无所有,但以\Q

开头的引用结束

所有pattern.quote所做的工作就是用\Q\E包装输入以产生文字化的字符串。

引用quote上的Java文档

  

返回指定字符串的文字模式字符串。这个   方法产生一个可用于创建模式的字符串   将匹配字符串s,就好像它是文字模式一样。
  输入序列中的元字符或转义序列将给出   没有特殊含义。

从技术上讲,从\Q(不包括)到下一个\E(不包括)(可能包括任意数量的\Q序列)的所有内容都被字面化。

当您在字符类中转义或引用连字符时(或放在末尾),它将失去其特殊含义,即定义一个范围,并且它变成了您自己演示的文字连字符:

String regex = "[a\\-z]";
Pattern p = Pattern.compile(regex);
String[] tests = {
    "-"
    , "a"
    , "b"
    , "z"
};
for (String test : tests) {
    System.out.println(" matching " + test + ":" + p.matcher(test).matches());
}

输出:

 matching -:true
 matching a:true
 matching b:false
 matching z:true

答案 1 :(得分:0)

我现在可以确认,\Q\E(以及Pattern.quote())除了在字符类中引用元字符 外,还将很有用外部角色类。我以为它仅适用于角色类之外,并且理解是错误的。我希望文档能更清楚地说明这一点。