20230626 2.1. 正则表达式
正则表达式
正则表达式( regular expression ) 用于指定字符串的模式,你可以在任何需要定位匹配某种特定模式的字符串的情况下使用正则表达式
[Jj]ava.+
匹配下列形式的所有字符串:
- 第一个字母是
J
或j
- 接下来三个字母是
ava
- 字符串的其余部分由一个或多个任意的字符构成
对于大多数情况,一小部分很直观的语法结构就足够用了
- 字符类( character class )是一个括在括号中的可选择的字符集,例如,
[Jj]
、[0-9]
、[A-Za-z]
、[^0-9]
。这里-
表示一个范围(所有 Unicode 值落在两个边界范围之内的字符),而^
表示补集(除了指定字符之外的所有字符) - 如果字符类中包含
-
,那么它必须是第一项或最后一项;如果要包含[
,那么它必须第一项;如果要包含^
,那么它可以是除开始位置之外的任何位置。其中,你只需要转义[
和\
- 有许多预定的字符类,例如
\d
(数字)和\p{Sc}
(Unicode 货币符号)
正则表达式语法分为:
- 字符
- 字符类
- 序列和选择
- 群组
- 量词
- 边界匹配
字符表达式 | 描述 | 示例 |
---|---|---|
c ,除 `.*+?{ |
()[^ | 字符表达式 |
----------------------------------------------------------- | ------------------------------------------------------------ | ------------------------------- |
之外 | 字符 c |
] |
. |
任何除行终止符之外的字符,或者在 DOTALL 标志被设置时表示任何字符 | |
\x{p} |
十六进制码为 p 的 Unicode 码点 | \x{1D546} |
\uhhhh 、 \xhh 、 \0o 、 \0oo 、 \0ooo |
具有给定十六进制或八进制值的码元 | \uFEFF |
\a 、\e 、\f 、\n 、\r 、\t |
响铃符( \x{7} )、转义符( \x{18} )、换页符( \x{8} ) 、换行符( \x{A} ) 、回车符( \x{D} )、指标符( \x{9} ) |
\n |
\cc ,其中 c 在 [a-z] 的范围内,或者是 @[\]^_? 之一 |
对应于字符 c 的控制字符 |
\cH 是退格符( \x{8} ) |
\c ,其中 c 不在 [A-Za-z0-9] 的范围内 |
字符 c |
\\ |
\Q...\E |
在左引号和右引号之间的所有字符 | \Q(...)\E 匹配字符串 (...) |
- 大部分字符都可以与它们自身匹配
.
符号可以匹配任何字符(有可能不包括行终止符 ,这取决于标志的设置)- 使用
\
作为转义字符,例如,\.
匹配句号而\\
匹配反斜线 ^
和$
分别匹配一行的开头和结尾- 如果
X
和Y
是正则表达式,那么XY
表示 “任何 X 的匹配后面跟随 Y 的匹配”,X | Y
表示“任何 X 或 Y 的匹配” - 可以将量词运用到表达式 X :
X+
(一个或多个)、X*
( 0 个或多个)与X?
( 0 个或 1 个) - 默认情况下,量词要匹配能够使整个匹配成功的最大可能的重复次数。你可以修改这种行为,方法是使用后缀
?
(使用勉强或吝啬匹配,也就是匹配最小的重复次数)或使用后缀+
(使用占有或贪婪匹配, 也就是即使让整个匹配失败,也要匹配最大的重复次数) - 使用群组来定义子表达式,其中群组用括号
()
括起来。例如,([+-]?)([0-9]+)
。然后可以询问模式匹配器,让其返回每个组的匹配,或者用\
来引用某个群组,其中n
是群组号(从\1
开始)
在使用正则表达式的各种程序和类库之间,表达式语法并未完全标准化
正则表达式的最简单用法就是测试某个特定的字符串是否与它匹配:
Pattern pattern = Pattern.compile(patternString);
Matcher matcher = pattern.matcher(input);
if (matcher.matches()) {
// do something
}
input
可以是任何实现了 CharSequence
接口的类的对象,例如 String
、StringBuilder
、CharBuffer
在编译这个模式时,可以设置一个或多个标志:
Pattern pattern = Pattern.compile(expression,
Pattern.CASE_INSENSITIVE + Pattern.UNICODE_CASE);
或者可以在模式中指定它们:
String regex = "(?iU:expression)";
Pattern.CASE_INSENSITIVE
或r
:匹配字符时忽略字母的大小写,默认情况下,这个标志只考虑 US ASCII 字符Pattern.UNICODE_CASE
或u
:当与CASE_INSENSITIVE
组合使用时,用 Unicode 字母的大小写来匹配Pattern.UNICODE_CHARACTER_CLASS
或U
:选择 Unicode 字符类代替 POSIX ,其中蕴含了UNICODE_CASE
Pattern.MULTILINE
或m
:^
和$
匹配行的开头和结尾,而不是整个输入的开头和结尾Pattern.UNIX_LINES
或d
:在多行模式中匹配^
和$
时,只有\n
被识别成行终止符Pattern.DOTALL
或s
:当使用这个标志时,.
符号匹配所有字符,包括行终止符Pattern.COMMENTS
或x
:空白字符和注释(从#
到行末尾)将被忽略Pattern.LITERAL
:该模式将被逐字地采纳,必须精确匹配,因字母大小写而造成的差异除外Pattern.CANON_EQ
:考虑 Unicode 字符规范的等价性,例如,u
后面跟随¨
(分音符号)匹配ü
如果想要在集合或流中匹配元素,那么可以将模式转换为谓词:
Stream<String> strings = Stream.of("a", "b", "c");
Stream<String> result = strings.filter(pattern.asPredicate());
如果正则表达式包含群组,那么 Matcher
对象可以揭示群组的边界
public int start(int group)
public int end(int group)
可以直接通过调用下面的方法抽取匹配的字符串:
public String group(int group)
群组 0 是整个输入,而用于第一个实际群组的群组索引是 1 。 调用 groupCount
方法可以获得全部群组的数量。对于具名的组,使用下面的方法
public int start(String name)
public int end(String name)
public String group(String name)
嵌套群组是按照前括号排序的
假设有模式 (([1-9]|1[0-2]):([0-5][0-9]))[ap]m
和输出 11:59am
String expression = "(([1-9]|1[0-2]):([0-5][0-9]))[ap]m";
String input = "11:59am";
Pattern pattern = Pattern.compile(expression);
Matcher matcher = pattern.matcher(input);
if (matcher.matches()) {
int count = matcher.groupCount();
System.out.println(count);
for (int i = 0; i <= count; i++) {
System.out.println("=================" + i);
System.out.println("start :: " + matcher.start(i));
System.out.println("end :: " + matcher.end(i));
System.out.println("group :: " + matcher.group(i));
}
}
输出:
3
=================0
start :: 0
end :: 7
group :: 11:59am
=================1
start :: 0
end :: 5
group :: 11:59
=================2
start :: 0
end :: 2
group :: 11
=================3
start :: 3
end :: 5
group :: 59
通常,你不希望用正则表达式来匹配全部输人,而只是想找出输入中一个或多个匹配的子字符串。这时可以使用 Matcher
类的 find
方法来查找匹配内容,如果返回 true
,再使用 start
和 end
方法来查找匹配的内容,或使用不带引元的 group
方法来获取匹配的字符串
String expression = "[ap]m";
String input = "11:59am";
Pattern pattern = Pattern.compile(expression);
Matcher matcher = pattern.matcher(input);
while (matcher.find()) {
String match = matcher.group();
System.out.println(match); // am
}
Matcher
类的 replaceAll
方法将正则表达式出现的所有地方都用替换字符串来替换,将所有的数字序列都替换成#
字符
Pattern pattern = Pattern.compile("[0-9]+");
Matcher matcher = pattern.matcher(input);
String output = matcher.replaceAll("#");
替换字符串可以包含对模式中群组的引用: $n
表示替换成第 n 个群组, ${name}
被替换为具有给定名字的组,因此我们需要用 \$
来表示在替换文本中包含一个 $
字符
如果字符串中包含 $
和 \
,但是又不希望它们被解释成群组的替换符,那么就可以调用
matcher.replaceAll(matcher.quoteReplacement(str));
replaceFirst
方法将只替换模式的第一次出现
Pattern
类有一个 split
方法,它可以用正则表达式来匹配边界,从而将输入分割成字符串数组
如果有多个标记,那么可以惰性地获取它们:
Stream<String> token = pattern.splitAsStream(input);
如果不关心预编译模式和惰性获取,那么可以使用 String.split
方法
String[] tokens = input.split("\\s*,\\s*");
java.util.regex.Pattern 方法名称 |
方法声明 | 描述 |
---|---|---|
compile |
public static Pattern compile(String regex) public static Pattern compile(String regex, int flags) |
把正则表达式字符串编译到一个用于快速处理匹配的模式对象中 |
matcher |
public Matcher matcher(CharSequence input) |
返回 matcher 对象,你可以用它在输入中定位模式的匹配 |
split splitAsStream |
public String[] split(CharSequence input) public String[] split(CharSequence input, int limit) public Stream<String> splitAsStream(final CharSequence input) |
将输入分割成标记,其中模式指定了分隔符的形式。 返回标记数组,分隔符并非标记的一部分 |
java.util.regex.Matcher 方法名称 |
方法声明 | 描述 |
---|---|---|
matches |
public boolean matches() |
如果输入匹配模式, 返回 true |
lookingAt |
public boolean lookingAt() |
如果输入的开头匹配模式, 返回 true |
find |
public boolean find() public boolean find(int start) |
尝试查找下一个匹配,如果找到了另一个匹配,则返回 true start :开始查找的索引位置 |
start end |
public int start() public int end() |
返回当前匹配的开始索引和结尾之后的索引位置 |
group |
public String group() |
返回当前的匹配 |
groupCount |
public int groupCount() |
返回输入模式中的群组数量 |
start end |
public int start(int group) public int end(int group) |
返回当前匹配中给定群组的开始和结尾之后的位置group :群组索引(从 0 开始),或者表示整个匹配的 0 |
group |
public String group(int group) |
返回匹配给定群组的字符串 |
replaceAll replaceFirst |
public String replaceAll(String replacement) public String replaceFirst(String replacement) |
返回从匹配器输入获得的通过将所有匹配或第一个匹配用替换字符串替换之后的字符串replacement :替换字符串,它可以包含用 $n 表示的对群组的引用,这时需要用 \$ 来表示字符串中包含一个 ` |
---------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
matches |
public boolean matches() |
如果输入匹配模式, 返回 true |
lookingAt |
public boolean lookingAt() |
如果输入的开头匹配模式, 返回 true |
find |
public boolean find() public boolean find(int start) |
尝试查找下一个匹配,如果找到了另一个匹配,则返回 true start :开始查找的索引位置 |
start end |
public int start() public int end() |
返回当前匹配的开始索引和结尾之后的索引位置 |
group |
public String group() |
返回当前的匹配 |
groupCount |
public int groupCount() |
返回输入模式中的群组数量 |
start end |
public int start(int group) public int end(int group) |
返回当前匹配中给定群组的开始和结尾之后的位置group :群组索引(从 0 开始),或者表示整个匹配的 0 |
group |
public String group(int group) |
返回匹配给定群组的字符串 |
符号 | ||
quoteReplacement |
public static String quoteReplacement(String s) |
引用 str 中的所有 \ 和 ` |
---------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
matches |
public boolean matches() |
如果输入匹配模式, 返回 true |
lookingAt |
public boolean lookingAt() |
如果输入的开头匹配模式, 返回 true |
find |
public boolean find() public boolean find(int start) |
尝试查找下一个匹配,如果找到了另一个匹配,则返回 true start :开始查找的索引位置 |
start end |
public int start() public int end() |
返回当前匹配的开始索引和结尾之后的索引位置 |
group |
public String group() |
返回当前的匹配 |
groupCount |
public int groupCount() |
返回输入模式中的群组数量 |
start end |
public int start(int group) public int end(int group) |
返回当前匹配中给定群组的开始和结尾之后的位置group :群组索引(从 0 开始),或者表示整个匹配的 0 |
group |
public String group(int group) |
返回匹配给定群组的字符串 |
|
| reset
| public Matcher reset()
public Matcher reset(CharSequence input)
| 复位匹配器的状态。第二个方法将使匹配器作用于另一个不同的输入。这两个方法都返回 this
|
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
2020-01-13 20200113 SpringBoot整合MyBatis