<Java>25 正则表达式
本文最后更新于:2022年6月19日 晚上
25 正则表达式
正则表达式:对字符串执行模式匹配的技术。一个正则表达式,就是用某种模式去匹配字符串的一个公式。除 Java 外,还有许多语言支持正则表达式。
String content = "HeruinKCoin"; //对象文本
String regular = "[A-Z]"; //[1] 创建规则
Pattern pattern = Pattern.compile(regular); //[2] 创建模式对象
Matcher matcher = pattern.matcher(content); //[3] 创建匹配器
while (matcher.find()){ //[4] find() 是否找到下一个
System.out.println(matcher.group(0)); //[5] group(0) 输出找到的当前对象
}
Matcher
底层维护了一个group[]
数组。如果 [4] 在文本里匹配到对象,会在group[0]
记载该起始位置 n1,在group[1]
记录该结束位置的下一位 n2。即 [n1,n2) 为匹配的字符串,n2 位置是下次匹配的起始位置。当 [1] 创建的规则包含分组(如
String regular = "(\\d\\d)(\\d\\d)";
),则第一组的起止位置记录在group[2]
、group[3]
,第二组在group[4]
、group[5]
。以此类推。这时,[5] 的group(0)
代表输出全部,group[1]
代表输出第一组,以此类推。
25.1 语法
元字符
- 限定符
- 选择匹配符
- 分组组合和反向引用符
- 特殊字符
- 字符匹配符
- 定位符
25.1.1 转义符号 \
使用正则表达式去检索某些特殊字符时,需要加上转义符号(如:(
需要写成 \(
)
在 Java 的正则表达式中,\\
代表一个 \
。——见 [1.8 Java 转义字符 ]
需要用到转义符号的字符有:.
、+
、(
、)
、$
、/
、\
、?
、[
、]
、^
、{
、}
25.1.2 字符匹配符
符号 | 含义 | 示例 | 解释 |
---|---|---|---|
[ ] |
可接收的字符列表 | [abcd] |
abcd 中的任一字符 |
[^] |
不接收的字符列表 | [^abcd] |
非 abcd 的任意字符 |
- |
连字符 | [a-z] |
a - z 中的任意字符 |
. |
匹配除 \n 外的任意字符 |
a..b |
a 开头,b结尾,中间含 2 字符 |
\d |
匹配单个数字字符 | \d{3} |
包含 3 个数字 |
\D |
匹配单个非数字字符 | \D(\d)* |
单个非数字字符开头,后接任意个数字字符 |
\w |
匹配单个数字、大小写字母字符 | \w{2}\d{3} |
2 个数字字母字符开头,后接 3 个数字字符 |
\W |
匹配单个非数字、非大小写字母字符 | \W+\d{2} |
以至少 1 个非数字字母字符开头,后接 2 个数字字符 |
\s |
匹配空白字符(空格、制表位等) | ||
\S |
匹配非空白字符 |
-
关于
.
:特别地,出现[.]
的场合,那个小圆点依然表示小圆点。[?]
同理,表示问号 -
正则表达式默认区分大小写。要不区分大小写,就加上
(?i)
-
(?i)abc
:即 abc 都不区分大小写 -
a(?i)bc
:即仅 bc 不区分大小写 -
a((?i)b)c
:即仅 b 不区分大小写 -
创建模式对象时,若如此做:
Pattern pattern = Pattern.compile(regular, Pattern.CASE_INSENSITIVE);
这个场合,也能不区分大小写。
-
25.1.3 选择匹配符 |
……我的感想是,和 Java 的逻辑或 |
一样!
25.1.4 限定符
符号 | 含义 | 示例 | 解释 |
---|---|---|---|
* |
指定字符重复任意次(可以为 0 次) | (abc)* |
仅包含任意个 abc 字符串的字符串 |
+ |
指定字符重复至少一次 | m+(abc)* |
以任意个 m 开头,后面可以有 abc 字符串的字符串 |
? |
指定字符重复最多一次(可以为 0 次) | m+abc? |
以任意个 m 开头,后面可以有最多一个 abc 字符串的字符串 |
{n} |
n 个匹配 | [abc]{3} |
长度为 3 的 abc 中的任意字符的组合 |
{n,} |
至少 n 个匹配 | [abc]{3,} |
长度不小于 3 的 abc 中的任意字符的组合 |
{n,m} |
n 到 m 个匹配 | [abc]{3,5} |
长度介于 3 到 5 之间的 abc 中的任意字符的组合 |
-
Java 的匹配模式默认是贪婪匹配。即:
aaaaa
匹配a{3,5}
的场合,会匹配到aaaaa
希望实现非贪婪匹配,可以添加额外的
?
。如:*?
、+?
、??
代表各自规则的非贪婪匹配
25.1.5 定位符
符号 | 含义 | 示例 | 解释 |
---|---|---|---|
^ |
指定起始字符 | ^[0-9]+[a-z]* |
至少一个数字开头,后接任意小写字母字符串 |
& |
指定结束字符 | ^[0-9][a]$ |
一个数字开头,一个 a 结尾 |
\b |
匹配目标字符串的边界 | K\.C\b |
匹配边界的 K.C |
\B |
匹配目标字符串的非边界 | K\.C\B |
匹配非边界的 K.C |
- 边界即字符串的末尾,或字符串中空格间隔的子串的末尾。
25.1.6 分组
符号 | 含义 |
---|---|
(pattern) |
非命名捕获。捕获匹配的字符串。 |
(?<name>pattern) 、(?'name'pattern) |
命名捕获。用于 name 的字符串不能包含标点符号,也不能以数字开头 |
- 编号为 0 的第一个捕获是由整个正则表达式匹配的文本。其他捕获结果根据左括号的顺序从 1 开始自动编号。
25.1.7 非捕获分组
符号 | 含义 | 示例 | 解释 |
---|---|---|---|
(?:pattern) |
匹配 pattern 但不捕获该匹配的子表达式。 | `industr(?:y | ies)` |
(?=pattern) |
匹配处于 pattern 前的搜索字符串。非捕获分组。 | `Windows(?=7 | 10 |
(?!pattern) |
匹配不处于 pattern 前的搜索字符串。非捕获分组。 | `Windows(?!7 | 10 |
25.2 常用类
-
Pattern
类:Pattern
对象是一个正则表达式对象,该类没有公共构造方法。用
Pattern.compile(reg)
获取一个Pattern
对象。 -
Matcher
类:Matcher
对象是输入字符串进行解释和匹配的引擎,也没有公共构造方法。用
Pattern
对象的matcher(content)
方法获得一个Matcher
对象。 -
PatternSyntaxExcption
类:PatternSyntaxExcption
是一个非强制异常类,表示一个正则表达式中的语法错误。
25.2.1 Pattern
类常用方法
-
Pattern.matches(reg, content)
:整体匹配,输入的字符串是否符合表达式。返回布尔值。matcher.matches()
:整体匹配,字符串是否符合表达式。返回布尔值。前面的方法实际上就是这个方法。 -
Pattern.compile(reg)
:返回一个指定表达式的Pattern
对象 -
pattern.matcher(content)
:返回一个字串的Matcher
对象 -
matcher.pattern()
:返回该Matcher
对象的表达式pattern.pattern()
:返回该Pattern
对象的表达式 -
matcher.find()
:尝试查找下一个匹配的序列,返回布尔值matcher.find(int)
:重置该匹配器,从指定索引位置开始重新查找 -
matcher.start()
:返回本次匹配的字符起始位置的索引matcher.end()
:返回本次匹配的字符结束位置 + 1 的索引这个场合,
content.substring(matcher.start(), matcher.end())
就是匹配的字符串 -
matcher.start(int)
:返回本次匹配的字符的该组内容的起始位置的索引matcher.end(int)
:返回本次匹配的字符的该组内容的结束位置 + 1 的索引 -
matcher.replaceAll(str)
:替换匹配到的全部内容matcher.replaceFirst(str)
:替换第一次匹配到的内容这些场合,返回的字符串才是替换后的字符串。原字符串不变。
25.3 分组、捕获、反向引用
-
分组(子表达式)
-
捕获:把正则表达式中,子表达式(分组)的内容保存到内存中以数字编号或显式命名的组里,方便后面引用。以分组的左括号为标志,第一组组号为 1,第二组为 2,以 0 代表整个正则表达式。
-
反向引用:分组的内容被捕获后,可以在这个括号后使用。这种引用既可以是在正则表达式内部,也可以在外部。内部反向引用
\分组号
、外部反向引用$分组号
String regular = "(\\w)\\1+"; //即,重复的字母或数字 Matcher matcher = Pattern.compile(regular).mathcer(content); content = matcher.replaceAll("$1"); //这样,就完成了去重
25.4 在 String
中使用正则表达式
str.matches(reg)
:整体匹配str.replaceAll(reg, reg)
:替换匹配到的全部内容str.split(reg)
:分割内容