Java正则表达式要点和案例

Posted on 2022-09-24

概述

正则表达式是文本处理的一大利器。在文本的校验、查找、替换三个场景下有巨大的代码提效效果,本文主要介绍JDK中java.util.regex包提供的对正则表达式的支持。

java.util.regex有三个核心类:

  1. Pattern类:Pattern是一个正则表达式的编译表示。 Pattern类是一个比较重的类,它的初始化伴随着正则解析。它是线程安全的,使用过程中注意单例、重用。避免性能问题~
  2. Matcher类:Matcher是对输入字符串进行解释和匹配操作的引擎。
  3. PatternSyntaxException:PatternSyntaxException是一个非强制异常类,它表示一个正则表达式模式中的语法错误。

需要格外注意一点,在Java正则中使用反斜杠”“时必须写成 "\\"。这是因为javac编译器在编译字符串处理转义字符时中会消费掉一个"\",剩下一个"\"会在Pattern编译表达式字符串处理转义字符时被消费掉。

原理可参考:https://www.cnblogs.com/lingyejun/p/11337141.html

Pattern类

Pattern类没有公共构造方法。要创建一个Pattern对象,你必须首先调用其**静态方法compile,加载正则规则字符串,然后返回一个Pattern对象。

Pattern类一样,Matcher类也没有公共构造方法。你需要调用Pattern对象的matcher方法来获得一个Matcher对象。

Pattern和Matcher的初始化:

Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(content);

Matcher类

Matcher类是正则操作过程中维护状态机的类,它是线程不安全的。

Matcher类有三类功能:

  • 校验
  • 查找
  • 替换

正则校验

为了检查文本是否与正则规则匹配,Matcher提供了以下几个返回值为boolean的方法。

序号 方法及说明
1 public boolean lookingAt()尝试将从区域开头开始的输入序列与该模式匹配。
2 public boolean find()尝试查找与该模式匹配的输入序列的下一个子序列。
3 public boolean find(int start)重置此匹配器,然后尝试查找匹配该模式、从指定索引开始的输入序列的下一个子序列。
4 public boolean matches()尝试将整个区域与模式匹配。

案例:lookingAt vs find vs matches

public static void main(String[] args) {
    checkLookingAt("hello", "helloworld");
    checkLookingAt("world", "helloworld");
    checkFind("hello", "helloworld");
    checkFind("world", "helloworld");
    checkMatches("hello", "helloworld");
    checkMatches("world", "helloworld");
    checkMatches("helloworld", "helloworld");
}


private static void checkLookingAt(String regex, String content) {
    Pattern p = Pattern.compile(regex);
    Matcher m = p.matcher(content);
    if (m.lookingAt()) {
        System.out.println(content + "\tlookingAt: " + regex);
    } else {
        System.out.println(content + "\tnot lookingAt: " + regex);
    }
}


private static void checkFind(String regex, String content) {
    Pattern p = Pattern.compile(regex);
    Matcher m = p.matcher(content);
    if (m.find()) {
        System.out.println(content + "\tfind: " + regex);
    } else {
        System.out.println(content + "\tnot find: " + regex);
    }

}


private static void checkMatches(String regex, String content) {
    Pattern p = Pattern.compile(regex);
    Matcher m = p.matcher(content);
    if (m.matches()) {
        System.out.println(content + "\tmatches: " + regex);
    } else {
        System.out.println(content + "\tnot matches: " + regex);
    }

}

输出

helloworld        lookingAt: hello

helloworld        not lookingAt: world

helloworld        find: hello

helloworld        find: world

helloworld        not matches: hello

helloworld        not matches: world

helloworld        matches: helloworld

说明

regex = “world” 表示的正则规则是以world开头的字符串,regex = “hello” 和regex = “helloworld” 也是同理。

  • lookingAt方法从头部开始,检查content字符串是否有子字符串和正则规则匹配。

相当于正则表达式前面加了 "^"

  • find方法检查content字符串是否有子字符串和正则规则匹配,不管字符串所在位置。
  • matches方法检查content字符串整体是否与正则规则匹配。

相当于正则表达式前面加了 "^"后面加了"$"

正则查找

为了查找文本匹配正则规则的位置,Matcher提供了以下方法:

序号 方法及说明
1 public int start() 返回以前匹配的初始索引。
2 public int start(int group)返回在以前的匹配操作期间,由给定组所捕获的子序列的初始索引
3 public int end() 返回最后匹配字符之后的偏移量。
4 public int end(int group)返回在以前的匹配操作期间,由给定组所捕获子序列的最后字符之后的偏移量。
5 public String group() 返回前一个符合匹配条件的子序列。
6 public String group(int group)返回指定的符合匹配条件的子序列。

案例:使用start()、end()、group()

public static void main(String[] args) {
    final String regex = "world";
    final String content = "helloworld helloworld";
    Pattern p = Pattern.compile(regex);
    Matcher m = p.matcher(content);
    System.out.println("content: " + content);
    int i = 0;
    while (m.find()) {
        i++;
        System.out.println("[" + i + "th] found");
        System.out.print("start: " + m.start() + ", ");
        System.out.print("end: " + m.end() + ", ");
        System.out.print("group: " + m.group() + "\n");
    }
}

输出

content: helloworld helloworld

[1th] found

start: 5, end: 10, group: world

[2th] found

start: 16, end: 21, group: world

正则替换

替换方法是替换输入字符串里文本的方法:

序号 方法及说明
1 public Matcher appendReplacement(StringBuffer sb, String replacement)\实现非终端添加和替换步骤。
2 public StringBuffer appendTail(StringBuffer sb) 实现终端添加和替换步骤。
3 public String replaceAll(String replacement)替换模式与给定替换字符串相匹配的输入序列的每个子序列。
4 public String replaceFirst(String replacement) 替换模式与给定替换字符串匹配的输入序列的第一个子序列。
5 public static String quoteReplacement(String s)返回指定字符串的字面替换字符串。这个方法返回一个字符串,就像传递给Matcher类的appendReplacement 方法一个字面字符串一样工作。

案例:replaceFirst vs replaceAll

public static void main(String[] args) {
    String regex = "can";
    String replace = "can not";
    String content = "I can because I think I can.";
    Pattern p = Pattern.compile(regex);
    Matcher m = p.matcher(content);
    System.out.println("content: " + content);
    System.out.println("replaceFirst: " + m.replaceFirst(replace));
    System.out.println("replaceAll: " + m.replaceAll(replace));

}

输出

content: I can because I think I can.

replaceFirst: I can not because I think I can.

replaceAll: I can not because I think I can not.

说明

replaceFirst:替换第一个匹配正则规则的子序列。

replaceAll:替换所有匹配正则规则的子序列。

总结

本文通过正则校验、正则查找、正则替换三个角度的API详解和案例详解说明了Java正则表达式的常用姿势和注意点,希望能给大家一些启示,帮助大家更好的使用正则工具~