java.util.Pattern的几种模式详细解析
前言
本地的JDK版本是1.8
本篇是我对于Pattern几种模式的一些个人理解,如果大家发现有异议的地方,欢迎大家评论指正
对于其中一些模式,使用了✔️、❌来表示是否能够匹配出结果
✔️ :表示能匹配出内容
❌ :表示不能匹配出内容
1️⃣ CASE_INSENSITIVE
参数描述:
1、忽略大小写,US-ASCII 字符集中的字符大小写不敏感(其实也就是忽略26个英文字母的大小写)
2、想要使UNICODE字符忽略大小写,可以和UNICODE_CASE
组合使用(该参数使用说明,请看下面的UNICODE_CASE
使用介绍)
3、指定该模式会有轻微的性能损失
🔶测试:
regex为helloworld
匹配 helloworld 和 helloWorld
正则表达式为helloworld | helloworld | helloWorld |
---|---|---|
使用CASE_INSENSITIVE | ✔️ | ✔️ |
不用CASE_INSENSITIVE | ✔️ | ❌ |
🔶 解释:
当不忽略大小写时,
helloWorld
无法被正则表达式helloworld
匹配出
🔶 底层代码:
使用了类ASCII
里面的转小写方法,将两个字符进行比较
ASCII.toLower(c1) != ASCII.toLower(c2)
2️⃣ UNICODE_CASE
参数描述:
1、忽略Unicode字符大小写 (默认情况下忽略大小写只支持US-ASCII字符)
2、指定此参数,会导致性能下降
大家都知道Unicode也叫做统一码,万国码,也就是多国字符的编码
世界上除了26个英文字母之外,还有其他的语言字母是有大小写的(比如希腊字母Ω的小写就是ω,Υ的小写字母是υ),所以需要这个参数
🔶 测试:
regex为helloworldΩ
匹配 helloworldω
正则表达式为helloworldΩ | helloworldω |
---|---|
使用 CASE_INSENSITIVE + UNICODE_CASE | ✔️ |
只使用CASE_INSENSITIVE | ❌ |
🔶 测试截图:
🔶 底层代码实现:
int cc1 = Character.toUpperCase(c1);
int cc2 = Character.toUpperCase(c2);
if (cc1 != cc2 && Character.toLowerCase(cc1) !=Character.toLowerCase(cc2))
return false;
3️⃣ COMMENTS
参数描述:
1、忽略空白
2、忽略#
后的字符直到行尾
🔶 测试(忽略空白):
regex为hello wo r l d
匹配 helloworld
正则表达式为hello wo r l d | helloworld |
---|---|
不使用COMMENTS | ❌ |
使用COMMENTS | ✔️ |
🔶 测试截图:
🔶 测试(忽略#
后面的字符直到行尾):
正则表达式 | 匹配内容:helloworld1 | |
---|---|---|
不使用COMMENTS | 使用COMMENTS | |
helloworld[0-9] | helloworld1 | helloworld1 |
hello wo rld [0-9] | helloworld1 | helloworld1 |
helloworld#[0-9] | ❌匹配不出结果 | helloworld |
helloworld # [0-9] | ❌匹配不出结果 | helloword |
🔶 解释:
该参数,会忽略掉表达式中的空格
以及 表达式中#后面的字符
原表达式为 | 使用COMMENTS后表达式变为 |
---|---|
hello wo rld [0-9] | helloworld[0-9] |
helloworld#[0-9] | helloworld |
helloworld # [0-9] | helloworld |
4️⃣ MULTILINE
参数描述:
1、在此参数下,正则表达式^
和$
会启用多行模式,默认情况下,正则表达式^
和$
忽略行终止符
🔶 测试:
regex为^world$
匹配 hello\nworld ,此处包含行终止符\n
正则表达式为^world$ | 匹配内容为:hello\nworld |
---|---|
使用 MULTILINE | 输出结果:world |
不使用MULTILINE | ❌ |
🔶 解释:
如果不使用
MULTILINE
,程序会将hello\nworld
作为一个整体进行匹配; 如果使用MULTILINE
,程序会根据行终止符号\n
将hello\nworld
分成hello
和world
然后匹配第一行的hello
,再匹配第二行的world
;
🔶 测试截图:
5️⃣ UNIX_LINES
参数描述(使用此参数后):
1、使用.
,^
和$
时,在此参数下,只能识别\n
为行终止符,其他的行终止符无法识别
UNIX_LINES
参数,我用MULTILINE
参数配合来测试,更容易懂,所以大家先要理解MULTILINE
参数的作用,再来看参数UNIX_LINES
🔶 测试:
测试内容 | 所选模式 | 正则表达式 ^world$ | 原因 |
---|---|---|---|
匹配结果 | |||
hello\u0085world | MULTILINE | world | \u0085 是行终止符 |
MULTILINE +UNIX_LINES | ❌匹配不出结果 | \u0085 不再被识别为行终止符 | |
hello\nworld | MULTILINE | world | \n 是行终止符 |
MULTILINE +UNIX_LINES | world | \n 是UNIX_LINES 模式下唯一被识别的行终止符 |
🔶 解释:
行终止符是一个或两个字符的序列,用于标记输入字符序列的一行的末尾。
下列都是行终止符(关于行终止符的问题,大家可以参考jdk的Pattern类的api文档):
🔹换行符(换行)字符( ‘\n
’ ),
🔹一个回车符,紧跟着一个换行符( “\r\n
” ),
🔹独立回车字符( ‘\r
’ ),
🔹下一行字符( ‘\u0085
’ ),
🔹行分隔符( ‘\u2028
’ )
🔹段落分隔符( '\u2029
’ )
如果UNIX_LINES
模式被激活,则\n
唯一识别的行终止符是换行符,\u0085
不再被识别为行终止符,所以无法匹配出来。
🔶 测试截图:
行终止符为
\u0085
行终止符为\n
6️⃣ LITERAL
参数描述:
1、在此模式下,输入字符串将被视为文字字符序列。 输入序列中的元字符或转义序列将没有特殊的含义。
2、只有CASE_INSENSITIVE
和UNICODE_CASE
能起到作用,其他都失效
🔶 测试:
测试内容 | 所选模式 | 正则表达式 .elloworld | 原因 |
---|---|---|---|
匹配结果 | |||
helloworld | 无 | helloworld | . 可以匹配除了\r 和\n 之外的任何字符,所以可以匹配h |
LITERAL | ❌匹配不出结果 | 在此模式下,. 被程序理解为字面意思,只能匹配点,所以无法匹配h | |
.elloworld | 无 | .elloworld | |
LITERAL | .elloworld |
🔶 测试截图:
7️⃣ DOTALL
参数描述:
1、.
将匹配任何字符,包含行终止符(默认情况下是不匹配行终止符)
此参数在平时还是比较常用的,大多数内容中都会包含行终止符
🔶 测试:
regex为hello(.*)world
匹配 hello\nworld ,此处包含行终止符\n
regex为hello(.*)world | hello\nworld |
---|---|
使用 DOTALL | ✔️ |
不使用DOTALL | ❌ |
🔶 测试截图:
8️⃣ CANON_EQ
参数描述:
1、启用规范等效
2、简单说,就是将一个字符分解,将多个字符组合成一个新的字符,再匹配,称之为标准化(比如光波长度和分子直径的常用计量单位Å
就可以拆分为A\u030A
)
3、指定此标志可能会造成性能损失
参考资料:
https://www.unicode.org/reports/tr15/tr15-23.html
🔶 测试:
regex为A\u030A
匹配 Å
regex为A\u030A | 匹配内容:Å |
---|---|
使用 CANON_EQ | 输出结果:Å |
不使用CANON_EQ | ❌ |
🔶 测试截图:
🔶 底层代码实现:
底层会调用Normalizer 类标准化传入进来的 regex,再进行匹配
Normalizer 类介绍
Normalizer.normalize(pattern, Normalizer.Form.NFD);
9️⃣ UNICODE_CHARACTER_CLASS
参数描述:
1、启用Unicode版本的预定义字符类和POSIX字符类(默认使用的US-ASCII)
2、使用该参数时,会默认启用UNICODE_CASE
参数识别大小写
3、指定此标志可能会造成性能损失
某些元字符(\b
、\d
、\s
、\w
、\B
、\D
、\S
、\W
),比如:
\d
默认表示的是ASCII中的数字,但在该参数下,它表示Unicode里的数字
\s
默认表示的是ASCII中的SPACE,但在该参数下,它表示Unicode里的WHITE_SPACE
\w
默认表示的是ASCII中的[A-Za-z0-9_]
,但在该参数下,它表示Unicode里的字符
🔶 测试:
正则表达式为\w+ | 匹配内容:ABC尤成军 |
---|---|
使用UNICODE_CHARACTER_CLASS | 输出结果:ABC |
不使用UNICODE_CHARACTER_CLASS | 输出结果:ABC尤成军 |
🔶 解释:
如果不使用UNICODE_CHARACTER_CLASS
,那么默认的ASCII
中是不会存在中文的,所有\w
是不能匹配中文
如果使用UNICODE_CHARACTER_CLASS
,Unicode中包含汉字,所以能匹配出尤成军
🔶 测试截图:
后语
以上是我的一些个人理解,如果大家有任何疑问或者发现有什么不对的地方,可以在下面评论,我会及时修改