如何掌握 Java 正则表达式 的基本语法及在 Java 中的应用

正则表达式是一种用于匹配字符串的模式,在许多编程语言中广泛使用。Java 正则表达式提供了强大的文本处理能力,能够对字符串进行查找、替换、分割等操作。

一、正则表达式的基本语法

正则表达式由普通字符和特殊字符组成。普通字符包括字母、数字和标点符号,而特殊字符(也称为元字符)则具有特殊意义,用于构建复杂的匹配模式。

1.1 普通字符

普通字符匹配自身。例如,正则表达式 abc 匹配字符串 "abc"。

1.2 元字符

元字符是正则表达式的核心部分,用于定义复杂的匹配模式。常见的元字符包括:

  • .:匹配任意一个字符(除换行符)。
  • ^:匹配字符串的开始。
  • $:匹配字符串的结束。
  • *:匹配前一个字符零次或多次。
  • +:匹配前一个字符一次或多次。
  • ?:匹配前一个字符零次或一次。
  • []:定义字符类,匹配其中任意一个字符。
  • |:表示“或”操作。
  • ():用于分组和捕获。
  • {}:用于限定重复次数。

    1.3 转义字符

    有些字符在正则表达式中有特殊意义,如果要匹配这些字符本身,需要使用反斜杠 \ 进行转义。例如,要匹配字符 .,应使用 \.。

    1.4 字符类

    字符类用于定义一个字符集合,匹配其中任意一个字符。常用的字符类包括:

    • [abc]:匹配字符 a、b 或 c。
    • [a-z]:匹配任意一个小写字母。
    • [A-Z]:匹配任意一个大写字母。
    • [0-9]:匹配任意一个数字。
    • [^abc]:匹配除 a、b、c 之外的任意一个字符。

      1.5 预定义字符类

      预定义字符类是一些常用字符类的简写形式,包括:

      • \d:匹配一个数字,等价于 [0-9]。
      • \D:匹配一个非数字字符,等价于 [^0-9]。
      • \w:匹配一个单词字符(字母、数字或下划线),等价于 [a-zA-Z0-9_]。
      • \W:匹配一个非单词字符,等价于 [^a-zA-Z0-9_]。
      • \s:匹配一个空白字符(空格、制表符、换行符等),等价于 [ \t\n\x0B\f\r]。
      • \S:匹配一个非空白字符,等价于 [^ \t\n\x0B\f\r]。

        1.6 边界匹配符

        边界匹配符用于匹配字符串中的边界位置,包括:

        • \b:匹配一个单词边界。
        • \B:匹配一个非单词边界。

          1.7 限定符

          限定符用于指定前一个字符或子模式的重复次数,包括:

          • *:匹配前一个字符零次或多次。
          • +:匹配前一个字符一次或多次。
          • ?:匹配前一个字符零次或一次。
          • {n}:匹配前一个字符恰好 n 次。
          • {n,}:匹配前一个字符至少 n 次。
          • {n,m}:匹配前一个字符至少 n 次,至多 m 次。

            1.8 捕获组和非捕获组

            捕获组用于将匹配的子模式存储起来,以便在后续操作中引用。非捕获组用于对子模式进行分组,但不存储匹配结果。

            • ():捕获组。
            • (?:):非捕获组。

              1.9 零宽断言

              零宽断言用于指定某个位置必须满足的条件,包括:

              • (?=):正向先行断言。
              • (?!:负向先行断言。
              • (?<=):正向后行断言。
              • (?二、Java 中的正则表达式 API

                Java 提供了 java.util.regex 包来支持正则表达式处理,其中最重要的类是 Pattern 和 Matcher。

                2.1 Pattern 类

                Pattern 类表示一个正则表达式的编译表示。常用的方法包括:

                • compile(String regex):编译给定的正则表达式。
                • matcher(CharSequence input):创建一个匹配器对象。

                  2.2 Matcher 类

                  Matcher 类用于对输入字符串进行模式匹配操作。常用的方法包括:

                  • matches():整个字符串是否与正则表达式匹配。
                  • find():是否找到与正则表达式匹配的子字符串。
                  • group():返回前一次匹配的子字符串。
                  • replaceAll(String replacement):替换所有匹配的子字符串。
                  • replaceFirst(String replacement):替换第一个匹配的子字符串。
                  • lookingAt():是否从字符串的开头开始匹配。

                    三、Java 正则表达式的常见用法

                    3.1 字符串匹配

                    3.1.1 完全匹配

                    要判断字符串是否完全匹配某个正则表达式,可以使用 Pattern 和 Matcher 类:

                    String regex = "\\d+";
                    String input = "12345";
                    Pattern pattern = Pattern.compile(regex);
                    Matcher matcher = pattern.matcher(input);
                    boolean isMatch = matcher.matches();
                    System.out.println("完全匹配: " + isMatch);
                    
                    3.1.2 子字符串匹配

                    要判断字符串中是否包含某个正则表达式匹配的子字符串,可以使用 find 方法:

                    String regex = "\\d+";
                    String input = "hello 12345 world";
                    Pattern pattern = Pattern.compile(regex);
                    Matcher matcher = pattern.matcher(input);
                    boolean found = matcher.find();
                    System.out.println("包含子字符串匹配: " + found);
                    

                    3.2 字符串替换

                    正则表达式可以用于替换字符串中的匹配部分。replaceAll 和 replaceFirst 方法用于替换所有匹配的子字符串或第一个匹配的子字符串:

                    String regex = "\\d+";
                    String input = "hello 12345 world";
                    String replacement = "number";
                    String result = input.replaceAll(regex, replacement);
                    System.out.println("替换结果: " + result);
                    

                    3.3 字符串分割

                    正则表达式可以用于根据模式分割字符串。String 类提供了 split 方法:

                    String regex = "\\s+";
                    String input = "hello   world   java";
                    String[] parts = input.split(regex);
                    System.out.println("分割结果: " + Arrays.toString(parts));
                    

                    3.4 捕获组

                    捕获组用于将匹配的子模式存储起来,以便在后续操作中引用。可以使用 group 方法获取捕获组的内容:

                    String regex = "(\\d{3})-(\\d{2})-(\\d{4})";
                    String input = "123-45-6789";
                    Pattern pattern = Pattern.compile(regex);
                    Matcher matcher = pattern.matcher(input);
                    if (matcher.matches()) {
                        String part1 = matcher.group(1);
                        String part2 = matcher.group(2);
                        String part3 = matcher.group(3);
                        System.out.println("捕获组: " + part1 + ", " + part2 + ", " + part3);
                    }
                    

                    3.5 零宽断言

                    零宽断言用于指定某个位置必须满足的条件,但不包括在匹配结果中。以下示例展示了正向先行断言:

                    String regex = "foo(?=bar)";
                    String input = "foobar";
                    Pattern pattern = Pattern.compile(regex);
                    Matcher matcher = pattern.matcher(input);
                    while (matcher.find()) {
                        System.out.println("零宽断言匹配: " + matcher.group());
                    }
                    

                    四、Java 正则表达式高级应用

                    4.1 动态构建正则表达式

                    有时我们需要根据不同的输入动态构建正则表达式。可以使用 StringBuilder 来拼接正则表达式:

                    String basePattern = "\\d";
                    int minDigits = 2;
                    int maxDigits = 4;
                    StringBuilder regex = new StringBuilder(basePattern);
                    regex.append("{").append(minDigits).append(",").append(maxDigits).append("}");
                    Pattern pattern = Pattern.compile(regex.toString());
                    String input = "123";
                    Matcher matcher = pattern.matcher(input);
                    boolean isMatch = matcher.matches();
                    System.out.println("动态构建正则表达式匹配: " + isMatch);
                    

                    4.2 正则表达式中的嵌套组

                    嵌套组用于在一个捕获组内再嵌套另一个捕获组,以下示例展示了嵌套组的用法:

                    String regex = "(\\d{2})((\\d{2}))";
                    String input = "1234";
                    Pattern pattern = Pattern.compile(regex);
                    Matcher matcher = pattern.matcher(input);
                    if (matcher.matches()) {
                        String outerGroup = matcher.group(1);
                        String nestedGroup = matcher.group(2);
                        String innermostGroup = matcher.group(3);
                        System.out.println("外部组: " + outerGroup + ", 嵌套组: " + nestedGroup + ", 最内部组: " + innermostGroup);
                    }
                    

                    4.3 分组命名和引用

                    Java 7 引入了分组命名功能,可以给捕获组命名,并通过名字引用:

                    String regex = "(?\\d{3})-(?
                    \\d{3})-(?\\d{4})";
                    String input = "123-456-7890";
                    Pattern pattern = Pattern.compile(regex);
                    Matcher matcher = pattern.matcher(input);
                    if (matcher.matches()) {
                        String areaCode = matcher.group("areaCode");
                        String prefix = matcher.group("prefix");
                        String lineNumber = matcher.group("lineNumber");
                        System.out.println("命名捕获组: " + areaCode + ", " + prefix + ", " + lineNumber);
                    }
                    

                    4.4 正则表达式的性能优化

                    在处理大型文本或复杂模式时,正则表达式的性能可能成为瓶颈。以下是一些性能优化建议:

                    • 避免回溯:尽量避免使用可能导致大量回溯的模式,如重复的捕获组。
                    • 预编译正则表达式:将正则表达式编译为 Pattern 对象,并重用该对象,而不是每次都重新编译。
                    • 使用非捕获组:在不需要捕获匹配内容时,使用非捕获组 (?:) 代替捕获组 ()。

                      4.5 正则表达式调试

                      调试正则表达式可能比较困难,可以使用在线工具(如 regex101)或集成开发环境(IDE)中的正则表达式调试功能来帮助理解和测试正则表达式。

                      掌握正则表达式可以大大提高文本处理的效率和灵活性,Java 提供的正则表达式 API 使得在程序中使用正则表达式变得简单高效。

                      黑马程序员免费预约咨询