Java 正则表达式详解
正则表达式,是一种用来描述字符串模式的规则,熟练掌握它可以让我们在数据处理、文本分析、表单验证等场景中事半功倍。Java语言内置了正则表达式API,我们可以利用它来处理字符串。本文将深入浅出地介绍Java中正则表达式的各种应用。
基础概念
正则表达式用一些特殊字符表示特定的文本模式,Java里的正则表达式就是一个字符串,我们可以使用String类型的matches()方法来匹配模式。其中,支持使用的特殊字符如下:
符号 | 描述 |
---|---|
. | 匹配除换行符以外的任意字符 |
^ | 匹配开头 |
$ | 匹配结尾 |
* | 匹配前一个字符0次或多次 |
+ | 匹配前一个字符1次或多次 |
? | 匹配前一个字符0次或1次 |
[] | 匹配其中任意一个字符 |
{} | 匹配固定次数 |
() | 标记一个子表达式 |
举个例子:我们要用正则表达式判断一个字符串是否是ip地址。它的模式可以表示成:^(25[0-5]|2[0-4]\d|[01]?\d{1,2})\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})$。其中,每个圆点前后都是固定的数字范围,圆点本身也需要转义(因为它是特殊字符)。
我们将使用这个例子来演示正则表达式各种应用,以及Java语言API的使用。
正则表达式的匹配
RegExp类提供了很多方法来帮助解析、匹配、搜索、拆分、替换文本。其中最常用的方法是matches(),它返回一个boolean类型的结果并用来判断字符串是否匹配模式。
String pattern = "^(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})$";
String input = "192.168.0.1";
if (input.matches(pattern)) {
System.out.println("This input is a valid IP address");
} else {
System.out.println("This input is not a valid IP address");
}
我们可以把上面的代码放到一个自己创建的Java文件(如RegexTester.java)中,编译并运行它,输入任意的IP地址都可以进行测试,如下:
$ javac RegexTester.java
$ java RegexTester
Please input an IP address: 192.168.0.1
This input is a valid IP address
正则表达式的拆分
另一个常见的应用是以某个字符串为分隔符,分割另一个字符串。比如我们将某个CSV文件进行导入处理,读取每一行,然后将文本内容按照,
分割。这个时候就应该使用Java API提供的split()方法,它接受一个正则表达式或字符串,返回一个字符串数组,包含拆分后的结果。
String content = "name,age,address\nTom,22,New York\nJane,25,London\nMike,33,Tokyo\n";
String[] lines = content.split("[\\r\\n]+");
for (String line : lines) {
String[] parts = line.split(",");
System.out.println("Name: " + parts[0] + ", Age: " + parts[1] + ", Address: " + parts[2]);
}
这段代码的输出结果如下:
Name: name, Age: age, Address:
Name: Tom, Age: 22, Address: New York
Name: Jane, Age: 25, Address: London
Name: Mike, Age: 33, Address: Tokyo
可以看到第一行并没有正确解析。这是因为我们只以\\r
和\\n
为分隔符,而实际的CSV文件可能是以其他字符分隔字段的,所以这里我们需要对输入的CSV文件进行先处理,去除可能会导致解析错误的字符。
正则表达式的替换
大规模的文本替换操作也是正则表达式的一个应用。Java API中,使用replaceAll()
方法即可完成替换操作,它接受两个参数,一个是待替换文本的正则表达式,另一个是替换后的文本。例如,我们需要将英文名字中的姓变为大写字母,可以如下处理:
String name = "Tom Smith";
String pattern = "^([a-zA-Z]+) ([a-zA-Z]+)";
String replaced = name.replaceAll(pattern, "1 " + "$2".toUpperCase());
System.out.println(replaced);
这段代码的输出结果是:Tom SMITH
。
正则表达式的搜索
正则表达式不仅可以进行匹配和替换,还可以用来搜索文本内容中是否存在某个模式的字符串。Java API中,使用Pattern
类表示正则表达式的模式,Matcher
类则提供了进行搜索的方法。下面是一个搜索某个文本文件中出现次数最多的词汇的例子:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class WordCounter {
private static final Pattern WORD_PATTERN = Pattern.compile("\\b[a-zA-Z]+\\b");
public static void main(String[] args) throws IOException {
String filename = "path/to/file.txt";
Map<String, Integer> wordCounts = new HashMap<>();
try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
String line;
while ((line = reader.readLine()) != null) {
Matcher matcher = WORD_PATTERN.matcher(line);
while (matcher.find()) {
String word = matcher.group().toLowerCase();
wordCounts.put(word, wordCounts.getOrDefault(word, 0) + 1);
}
}
}
String mostCommonWord = null;
int mostCommonCount = 0;
for (Map.Entry<String, Integer> entry : wordCounts.entrySet()) {
if (entry.getValue() > mostCommonCount) {
mostCommonCount = entry.getValue();
mostCommonWord = entry.getKey();
}
}
System.out.println("Most common word in " + filename + " is " + mostCommonWord + " with count " + mostCommonCount);
}
}
这个例子会读取指定的文本文件,使用正则表达式按单词拆分并累加出现次数,再统计出出现次数最多的单词。运行它后,输出结果如下:
Most common word in path/to/file.txt is the with count 26
结论
正则表达式是一种十分强大的模式匹配工具,利用Java内置的正则表达式API,我们可以方便地在程序中处理文本、搜索、替换等各种任务。尽管掌握它的学习曲线较为陡峭,但一旦熟练掌握后,就可以提高我们的生产力,减少我们的工作量。