正则表达式中的捕获组和模式拆分方法

Capturing groups and Pattern split method in regular expression

如何理解以下代码的输出?代码的前四个打印语句是关于 Java 中正则表达式中的捕获组,其余代码是关于 Pattern split 方法的。我参考了一些文档来理解代码的输出(如图所示),但无法弄清楚它究竟是如何工作和显示这个输出的。

Java代码

    import java.util.*;
    import java.util.regex.*;
    import java.lang.*;
    import java.io.*;

    /* Name of the class has to be "Main" only if the class is public. */
    public class Codechef
    {
        public static void main(String[] args) {
            //Capturing Group in Regular Expression
            System.out.println(Pattern.matches("(\w\d)\1", "a2a2")); //true
            System.out.println(Pattern.matches("(\w\d)\1", "a2b2")); //false
            System.out.println(Pattern.matches("(AB)(B\d)\2\1", "ABB2B2AB")); //true
            System.out.println(Pattern.matches("(AB)(B\d)\2\1", "ABB2B3AB")); //false
            // using pattern split method
            Pattern pattern = Pattern.compile("\W");
            String[] words = pattern.split("one@two#three:four$five");
            System.out.println(words);
            for (String s : words) {
                System.out.println("Split using Pattern.split(): " + s);
            }

        }
    }

结果

编辑-1

查询

If i talk about Capturing Groups, I cannot figure out what is usage of ‘’ or ‘’ here? How these are evaluating to true or false.

答案:

  • \1 重复第一个捕获的组(即 a2(\w\d) 捕获)
  • \2 重复第二个捕获组(即 B2(B\d) 捕获)

这些组合的实际名称是 backreferences:

The section of the input string matching the capturing group(s) is saved in memory for later recall via backreference. A backreference is specified in the regular expression as a backslash () followed by a digit indicating the number of the group to be recalled.


If i talk about Pattern split method, I wish to know how the string split is happening. How does this split method work differently than a normal string split method?

Answer:

The split() method in the Pattern class can split a text into an array of String's, using the regular expression (the pattern) as delimiter

这里您提供了一个更强大、更灵活的正则表达式,而不是使用修复字符串或字符显式拆分字符串。

第一个控制台打印行...

System.out.println(Pattern.matches("(\w\d)\1", "a2a2")); //true
System.out.println(Pattern.matches("(\w\d)\1", "a2b2")); //false
System.out.println(Pattern.matches("(AB)(B\d)\2\1", "ABB2B2AB")); //true
System.out.println(Pattern.matches("(AB)(B\d)\2\1", "ABB2B3AB")); //false

利用 matches() 方法,该方法始终 return 是一个布尔值(真或假)。此方法主要用于某种类型的字符串验证。以第一个和第二个示例正则表达式为例,它们都是:"(\w\d)\1" 然后通过 matches() 针对两个提供的字符串("a2a2""a2b2")对该表达式进行处理 方法,正如他们所做的那样,您肯定会按顺序 return 编辑布尔值 truefalse

这里真正的关键是知道 什么 那个特定的 Regular Expression 应该验证。上面的表达式仅适用于括号中表示的 1 个捕获组。 \\w 用于匹配任何单个 word 字符 等于 a-zA-Z0-9_(下划线字符)。 \\d 用于匹配等于从 09 的任何数字的单个数字。

Note: In reality the expression Meta characters are written as \w and \d but because the Escape Character (\) in Java Strings need to be escaped you have to add an additional Escape Character.

\1 用于查看是否存在与第一个捕获组最近匹配的相同文本的单个匹配项。由于只指定了一个捕获组,因此您只能在此处使用值 1。好吧,这并不完全正确,您可以在此处使用 0 的值,但您不会在任何捕获组中寻找匹配项,这会消除此处的目的。任何其他大于 1 的值都会产生表达式异常,因为您只有 1 个捕获组。

底线,表达式查看提供的字符串中的前两个字符:

  • 提供的字符串中的第一个字符 (\\w) 是大写还是小写 A 到 Z_0 到 9 之间的数字?如果不是,那么就没有匹配项并且布尔值 false 是 returned 但是,如果有那么......
  • 提供的字符串中的第二个字符 (\\d) 是一个数字 从 0 到 9?如果不是,那么布尔值 false 是 returned 但是,如果有那么....
  • 剩下的2个字符是否完全相同(包括字母 如果使用 a-zA-Z 的情况)。如果剩下的 2 个字符不是 相同或有两个以上的剩余字符然后布尔 false 是 returned。但是,如果剩下的两个字符相同,则 return boolean true.

基本上,该表达式仅用于验证提供的字符串中的 最后两个 字符是否与 匹配前两个 个相同提供字符串的字符。这就是为什么第二个控制台打印:

System.out.println(Pattern.matches("(\w\d)\1", "a2b2")); //false

return 是一个布尔值 falseb2a2 not 相同,而在第一个控制台打印:

System.out.println(Pattern.matches("(\w\d)\1", "a2a2")); //true

后两个字符a2确实匹配前两个 个字符 a2 因此布尔值 true 是 returned.

您现在会注意到在其他两个控制台打印中:

System.out.println(Pattern.matches("(AB)(B\d)\2\1", "ABB2B2AB")); //true
System.out.println(Pattern.matches("(AB)(B\d)\2\1", "ABB2B3AB")); //false

使用的正则表达式包含 2 个捕获组(两组括号)。同样类型的匹配适用于此处,但针对两个捕获组,而不是像前两个控制台打印那样的捕获组。

如果您想了解这些正则表达式如何发挥作用并获得有关表达式含义的解释,请使用 regex101.com. This is also a good Regular Expressions 资源中的正则表达式测试器。

Pattern.split():

在这种情况下,我认为使用 Pattern.split() 方法有点矫枉过正,因为 String.split( ) 接受正则表达式,但在其他领域也有它的用途。尽管如此,它还是如何使用它的一个很好的例子。这里使用 .split() 方法根据提供给它的字符串以及通过模式被视为正则表达式的内容进行分组,在这种情况下是 "\\W"(否则:\W)。 \W(大写 W)表示匹配任何 non-word 字符 不等于a-zA-Z0 -9_。这个表达式基本上与 "\w" 相反(小写 w)。字符 @#:$包含在提供的字符串中(是的...逗号、分号、感叹号等):

"one@two#three:four$five"

被认为是 non-word 个字符,因此对其中任何一个进行拆分,得到一个字符串数组,其中包含:

[one, two, three, four, five]

使用String.split() 方法,因为此方法允许应用正则表达式:

String[] s = "one@two#three;four$five".split("\W");

甚至:

String[] s = "one@two#three;four$five".split("[@#:$]");

甚至:

String[] s = "one@two#three;four$five".split("@|#|:|\$");
// The $ character is a reserved RegEx symbol and therefore
// needs to be escaped.

或不断...

是的... "\\W" 更容易,因为它涵盖了所有 non-word 个字符。 ;)