正则表达式笔记 5 捕获组与逆向引用 [Capturing Group and Back Reference]

时间:2022-04-10 21:46:45

Regex :

  • 本文主要讲述正则表达式中的捕获组(Capturing Group)的概念
  • 本文的正则表达式在 Java 中测试(需要注意的是这里的部分正则表达式在 Java7 中才能应用,下面会注明)
  • 本文正则表达式用           高亮标出

Capturing Group : (X)

简单的理解就是把正则表达式中的某部分用 () 括起来表示为一个组,纯理论解释不怎么好解释,详细还看下面的举例。

        举例:

  • (Ggi)cciGgicci 都匹配 "Ggicci",只不过前面把 Ggi 作为一个捕获组,在匹配到的同时它可以捕获 "Ggi" 这样的字符串供逆向引用(Back Reference),见下一栏。
  • Ggicci*(Ggicci)* 不同在于 Ggicci* 匹配的是 "Ggicci" 和 "Ggicci…i" 这种情况,而 (Ggicci)* 匹配的是 "Ggicci" 和 "GgicciGgicci…Ggicci" 这种情况。

Back Reference :

逆向引用指的是正则表达式中某个捕获组捕获到的字符串供正则表达式构建其自身匹配规则的方式。这是我自己归纳的理论,听起来肯定很晦涩,详细见下面讲解

        捕获组的编号与命名:

        如 ((A)(B(C))) “摘自Java7 Doc”,这里有 4 个组:

编号 捕获组
1 ((A)(B(C)))
2 (A)
3 (B(C))
4 (C)

        在未对捕获组人为命名的时候,对捕获组的编号是默认的从左到右依次萃取 ( 和与之对应成一对的 )。如上,一共 4 个 ( ,所以有 4 个组,按 ( 的出现次序编号。

  • (?<name>X) 命名捕获组为 name,在 Java7 中;
       1: String source = "Ggicci was born in 1991 and is 20 years old now. He weights 54kg and is 170cm tall.";        
       2: Pattern pattern = Pattern.compile("(?<user>[Gg]gicci)|(?<digital>\\d+)");        
       3: Matcher matcher = pattern.matcher(source);
       4: while (matcher.find()) {
       5:     System.out.println(matcher.group());
       6: }
    代码中的正则表达式(已加粗)匹配 Ggicci 或 ggicci 或一段数字,输出为:
       1: //输出:
       2: Ggicci
       3: 1991
       4: 20
       5: 54
       6: 170
    (?<user>[Gg]gicci) 把捕获组命名为 user,我们用 Matcher 类的 group(String name) 方法,即 matcher.group("user"); 可以获取该捕获组捕获的内容,其它的捕获组内容将为 null:
       1: System.out.println(matcher.group("user")); //替换上面 while 循环中的输出语句
       2: //输出:
       3: Ggicci
       4: null
       5: null
       6: null
       7: null
    当然用 Matcher 类的 group(int group) 方法也可以,这里 user 捕获组的默认编号为 1,所以 matcher.group(1) 同 matcher.group("user") 一样。(?<digital>\d+) 也同样去理解。
  • (?:X) 取消捕获组命名,注意这种方式连捕获组默认的编号也会取消,所以在调用 Matcher.group(int) 或 Matcher.group(String) 的时候会异常;
  • \n 表示引用第 n 个捕获组捕获到的内容;
       1: String source = "Hello, my my name is uh.. is is Gg.. ggicci ggicci ggicci ggicci";
       2: Pattern pattern = Pattern.compile("\\b(\\w+)\\b((\\s+)\\1\\b)+");
       3: Matcher matcher = pattern.matcher(source);
       4: while (matcher.find()) {
       5:     System.out.println(matcher.group());
       6: }
    这段正则表达式 \b(\w)\b((\s+)\1)+ 匹配字符串重复的以空格符间隔的单词。其中 \1 引用了捕获组 (\w) 匹配到的内容。比如 (\w) 第一次匹配了 "Hello",\1 引用了 "Hello" 后正则表达式其实已经变成了 \bHello\b((\s+)Hello)+ 了(这是从形式上去理解,具体内部机制如何,亲,我目前真的不知道 : )),但是显然后面没有 "Hello" 可以匹配了,(\w) 第二次匹配了 "my",\1 引用了 "my",找到匹配,然后依次下去,输出如下:
       1: //输出:
       2: my my
       3: is is
       4: ggicci ggicci ggicci ggicci
  • \k<name> 表示引用命名为 name 的捕获组捕获到的内容,在 Java7 中;
       1: //这里同上面的正则表达式一样,只不过给 \1 取了个名字叫 repeat
       2: //然后用 \k<repeat> 代替 \1 而已
       3: Pattern pattern = Pattern.compile("\\b(?<repeat>\\w+)\\b((\\s+)\\k<repeat>\\b)+");

End :

Author : Ggicci

Java 学习笔记整理,谢谢阅读,有误请指正!

正则表达式笔记 5 捕获组与逆向引用 [Capturing Group and Back Reference]