概述
正则表达式是文本处理的一大利器。在文本的校验、查找、替换三个场景下有巨大的代码提效效果,本文主要介绍JDK中java.util.regex
包提供的对正则表达式的支持。
java.util.regex
有三个核心类:
- Pattern类:
Pattern
是一个正则表达式的编译表示。Pattern
类是一个比较重的类,它的初始化伴随着正则解析。它是线程安全的,使用过程中注意单例、重用。避免性能问题~ - Matcher类:
Matcher
是对输入字符串进行解释和匹配操作的引擎。 - 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正则表达式的常用姿势和注意点,希望能给大家一些启示,帮助大家更好的使用正则工具~