正则表达式, regular expression,可以用来搜索和处理文本。
语法
正则表达式中有一些字符代表着特定的含义,比如+
表示匹配前面的字符/表达式0到多次。这种特定含义的字符,可以看做是正则表达式语言中的保留关键词
,有些资料中也称作为元字符
。有些元字符之间需要成对出现,例如 {
和 }
。元字符之前也可以搭配使用。有些元字符,在不同的使用场景中含义不同。
语法 | 说明 |
---|---|
^ | 匹配开始位置 |
$ | 匹配结束位置 |
\ | 转义 |
* | 匹配前面的字符/表达式 0 次或多次 |
+ | 匹配前面的字符/表达式 1 次或多次 |
? | 匹配前面的字符/表达式 0 次或1次。在 * 、+ 、? 、{m} 、{m,} 、{m,n} 之后出现时,代表匹配模式是非贪心的 。 |
. | 默认模式下, 匹配\r 、\n 外的所有单个字符。 |
{m} | 匹配前面的字符/表达式 m 次。 m >=0 。默认是贪心匹配 。 |
{m, n} | 匹配前面的字符/表达式 m 次到 n 次。 m >=0, n >= m。默认是贪心匹配 。 |
{m,} | 匹配前面的字符/表达式至少 m 次。 m >=0。默认是贪心匹配 。 |
a|b | 匹配 a 或者 b |
a|xyz | 匹配 a 或者 xyz |
[xyz] | 匹配 x 或者 y 或者 z |
[^xyz] | 匹配不是 x、y、z 的字符 |
[a-z] | 匹配 a 到 z 之间的字符,包含 a、z。 |
[^a-z] | 匹配不是 a 到 z 之间的字符,a、z 也不匹配。 |
[0-9] | 匹配 0 到 9 之间的字符,包含 0、9。 |
(pattern) | 匹配 pattern 对应的正则表达式,并生成捕获组 |
(?:pattern) | 匹配 pattern 对应的正则表达式,不生成捕获组 |
(?<groupName>pattern) |
匹配 pattern 对应的正则表达式,并生成捕获组 ,组名是groupName 。 |
\1 | 反向引用前面的编号为1的捕获组。不会生成捕获组。类似的,还有\2 、\3 等。 |
\b | 匹配单词边界。在英文中,单词之间用空格隔开。单词边界是指单词和空格之间的部分。这是一个抽象的概念,因为单词和空格之间的部分是看不到的。 |
\B | 匹配非单词边界。 |
\d | 匹配数字字符。即[0-9] |
\D | 匹配非数字字符。即[^0-9] |
\n | 匹配换行符 |
\r | 匹配回车符 |
\f | 匹配换页符 |
\t | 匹配制表符 |
\v | 匹配垂直制表符 |
\s | 配置空白符号。即[\n\r\f\t\v] |
\S | 匹配非空白符号 |
\w | 匹配字母、数字、下划线。即[A-Za-z0-9_] |
\W | 不匹配字母、数字、下划线。即[^A-Za-z0-9_] |
\x23 | 匹配 ascii 表中十六进制的 23 对应的字符。\x 后必须是2个16进制字符。 |
\u1234 | 匹配 16 进制的 1234 对应的 unicode 字符。\u 后必须是4个16进制字符。这是 UTF-16 的字符编码。表情符号以及一些生僻字,会需要两个\u才行。例如\ud83d\ude0a 对应 😊 。 |
其他字符 | 匹配对应的字符 |
贪心匹配
是尽可能多的匹配,非贪心匹配
是尽可能少的匹配。
转义规则
在正则表达式中?
代表匹配前面的字符/表达式0次或者1次。如果要匹配字符?
,那么正则表达式处理引擎应该看到的是\?
。我们在 Java 中书写的字符串形式的正则表达式应该是 \\?
。
要匹配字符\
,Java 中要写成\\\\
。
注意,在其他一些编程语言中,匹配字符?
,只需要\?
即可, \\?
反而是错误的。
使用 String 的 matches 方法判断字符串是否匹配正则表达式
matches 返回 boolen 值。
示例: 判断字符串中是否有英文句号.
\s
用于匹配空白字符,\S
匹配非空白字符。\.
用于匹配英文逗号.
示例: 判断字符串不为空,且只含有数字
示例: 判断字符串是整数或小数, 小数点后最多8位
012
也返回 true,在一些场景下,是不符合预期的。
示例: 判断字符串含有小数点,且小数点前后都是数字,且小数点前若有多个数字,最高位不能是0
示例: 判断字符串为空,或者仅由字母abc中的一个或多个组成
使用 Pattern.matches 方法判断字符串是否匹配正则表达式
String 的 matches 方法,底层调用的 Pattern.matches 方法。
Pattern.matches 方法源码:
使用示例:
使用 Pattern.compile 编译正则表达式
示例:
使用 Matcher 找到匹配正则表达式的字符串
示例: 使用 find(), start(), end()
find() 返回是否找到匹配正则表达式的字符串。start()、end() 返回所匹配的字符串的位置。
第一次执行 find() 时,会从字符串初始位置开始查找。在找到了匹配的字符串后,会变更下次查找的初始位置。
执行结果:
理解【捕获组】
在正则表达式中,可以应该能括号对匹配的内容进行分组。我们可以利用这个机制来提取我们需要的内容。
例如,正则表达式 ((a)(b(c)))
,会匹配 abc
这样的连续字符。组编号和内容如下:
组编号 | 内容 |
---|---|
1 | ((a)(b(c))) |
2 | (a) |
3 | (b(c)) |
4 | (c) |
示例: 获取捕获组的数量和每个组的内容
代码示例1:
执行结果:
注意, group(0)
是匹配的字符串,不算在捕获组中。
代码示例2:
执行结果:
代码示例3:
执行结果:
代码示例4:
执行结果:
示例: 命名捕获组
运行结果:
示例: 反向引用
执行结果:
String 的 replaceFirst、replaceAll 的特殊用法:调整捕获组位置
replaceFirst、replaceAll 的第一个参数是正则表达式,第二个参数是要替换的内容。但是第2个参数比较特殊, 在这里面$1
代表第1个捕获组的内容,$2
代表第2个捕获组的内容,依次类推。
如果要替换为字符串$1
,要写成\\$1
。
代码示例:
执行结果:
贪心匹配与非贪心匹配
贪心匹配
是尽可能多的匹配,非贪心匹配
是尽可能少的匹配。
*
、+
、?
、{m}
、{m,}
、{m,n}
默认是贪心匹配
。当?
出现在他们后面时,代表非贪心匹配
。
示例:贪心匹配
执行结果:
示例: 非贪心匹配
执行结果:
使用 String 的 replaceAll 替换掉符合正则表达式的字符串
replaceAll 会替换掉所有符合正则表达式的子字符串。
代码示例:
执行结果:
使用 String 的 replaceFirst 替换掉符合正则表达式的字符串
replaceFirst 会替换掉第一个符合正则表达式的子字符串。
代码示例:
执行结果:
使用 Pattern.DOTALL 让英文句号.
支持匹配\r
、\n
默认是不匹配换行符的。
代码示例:
执行结果:
Pattern.compile 设置模式为 Pattern.DOTALL 时,则支持匹配\r
、\n
。
代码示例:
执行结果:
使用 ^
、$
匹配开始位置和结束位置
示例: 使用 ^
匹配开始位置
执行结果:
只匹配到了 123, 没有匹配到 456。
###示例: 使用 $
匹配结束位置
代码示例1
执行结果:
代码示例2
执行结果:
为什么没有匹配到 456 ?因为默认情况下结束位置是指整个文本的结束位置,而不是每一行的结束位置。
若要匹配到456
,可以指定Pattern.MULTILINE
来实现。见下面的示例。
示例: 使用Pattern.MULTILINE
让 $
匹配每一行的结束位置
执行结果: