Java 正则表达式

描述

定义:用于描述文本/字符串的一组规则

作用:使用一些自定义的规则来批量处理文本,提取信息

优点:使用很少的代码完成复杂的文本提取工作,提高工作效率

缺点:难学,难懂。在 java 对于正则表达式的支持不太友好,频繁使用会有性能问题。

常见规则

元字符

^ 开始位置
$ 结束位置
. 单个任意字符
\w 单个”word”字符 字母/数字/下划线/汉字
\s 单个空白字符
\d 单个数字字符
\b 单词的开始或结束

重复

* 0次或多次
+ 1次或多次
? 0次或1次
{n} n次
{n,} >=n次
{n,m} n到m次

选择

[aeiou] 单个的a/e/i/o/u字符之一
[0-9] 单个数字字符
[A-Z] 单个大写字母
[A-Z0-9_] 大写字母或者数字或者下划线
Hi|hi等价于[Hh]i Hi或者hi

Java 世界中的正则表达式

Java 中的正则表达式是比较「昂贵」的

  • 正则表达式需要解析

    • Java 需要将正则表达式字符串,转换成自己内部的数据结构,这个转换过程代价较大
    • 在写代码中可以将正则表达式预编译好,需要的时候再调用就行了,减少了多次编译的开销。例:
      1
      private static final Pattern phoneNumber = Pattern.compile("0\\d{2}-[1-9]\\d{7}|0\\d{3}-[1-9]\\d{6}");
  • 匹配过程非常「昂贵」

    • Java 的匹配算法并不高效,用到的是回溯算法。就像机器人走迷宫一般,一直尝试,遇到墙就换一条路线继续试,直到走出迷宫

Java 中使用到正则表达式的方法:String 类中的 split,replaceAll,replacefirst,matches,以及 Matches 中的方法。可以查看相关的 demo 链接:判断是不是合法的固定电话号码移除文件中的时间戳

分组与捕获

前面的正则表达式用法,都是用来判断字符串是否满足条件。然而,实际工作中用到较多的都是从一堆字符串中提取所需的信息,那么 Java 又是怎么做的呢?

想要将所有符合正则表达式的⽂本抓出来处理,需要先了解如下规则:

  • 使⽤括号来指定⼀个被捕获的分组
  • 分组的编号从1开始
  • 分组的编号计算只看左括号
  • (?:)不捕获和分配编号,括号只⽤于分组或标记优先
  • 分组编号为0表示整个匹配的字符串

Java 中捕获数据

在 Java 中可以使用 Pattern 类的 matcher() 方法生成 Matcher 对象 ,然后我们可以对 Matcher对象进行操作

假设有如下数据,我们需要将时间以及消费金额提取出来。

1
2
3
2020-01-02 在家玩游戏消费0元
2020-01-03 在家敲代码消费3元
2020-02-02 出门旅游消费1000元

我们可以先将该数据读取出来,保存成一个 List

1
2
File gcLog = new File("message.log");
List<String> lines = Files.readAllLines(gcLog.toPath());

然后我们可以在类中声明 Pattern,把对匹配时间和事件的正则表达式预编译。经过在线正则表达式测试,我们可以编写如下正则 \d{4}-\d{2}-\d{2}(.*)?\d 这个可以匹配时间和金额。我们要提取,就需要给时间部分加上括号,金额部分也加上括号。正则表达式变成 (\d{4}-\d{2}-\d{2})(.*)?(\d)

1
2
private static final String MESSAGE_REGEX = "(\d{4}-\d{2}-\d{2})(.*)?(\d)";
private static final Pattern pattern = Pattern.compile(MESSAGE_REGEX);

接着对所有字符串进行匹配,匹配过程中会生成 Matcher。调用 Matcher 的 find 方法,判断是否匹配成功。因为分组编号为 0 代表匹配的全部信息,即日期+金额,group(1) 代表匹配的第一组信息,即时间,group(2)就代表金额。

1
2
3
4
5
6
7
8
for (String line : lines) {
Matcher matcher = pattern.matcher(line);
if(matcher.find()){
System.out.println(matcher.group(0));
System.out.println(matcher.group(1));
System.out.println(matcher.group(2));
}
}

一个更为复杂的 GC 日志文件信息提取操作可查看 Demo


Java 正则表达式
http://wszzf.top/2021/04/17/Java 正则表达式/
作者
Greek
发布于
2021年4月17日
许可协议