正则表达式
Java中的正则表达式工具包
包名:java.util.regex.用于匹配字符序列与正则表达式指定模式的类
接口:MatchResult:匹配操作的结果
类:
- Matcher:通过解释 Pattern 对 character sequence 执行匹配操作的引擎
- Pattern:正则表达式的编译表示形式。
- 示例:
1
2
3Pattern p = Pattern.compile("a*b");
Matcher m = p.matcher("aaaaab");
boolean b = m.matches();
正则表达式的基本语法 (部分参考)
由只代表自身的 字面值 和代表特定含义的 元字符 组成。
字面值:大部分字符,包括 字母数字字符,会以字面值的形式出现。这意味着它们 查找的是自身。比如,正则表达式 bobo
,就是先找到b,接着o,然后是b,最后找到o。
元字符
.
表示匹配任何单字符(与 行结束符 可能匹配也可能不匹配)- 任何 元字符 如果用一个 反斜杆
\
进行转义就会变成字面值 如果未指定 DOTALL 标志,则正则表达式
.
可以与任何字符(行结束符除外)匹配行结束符
- 一个或两个字符的序列,标记输入字符序列的行结尾。
- 新行(换行)符 (‘\n’)
- 后面紧跟新行符的回车符 (“\r\n”)
- 单独的回车符 (‘\r’)
- 下一行字符 (‘\u0085’)
- 行分隔符 (‘\u2028’)
- 段落分隔符 (‘\u2029)
\
反斜杠 是一个元字符,这意味着它也可以使用反斜杠转义。示例:b.b.
能够匹配bobo, b bb\.b\.
只能匹配b.b. 这里的.是字面值,不是元字符;b\\
只能匹配b\
这里\
也是字面值。上述.\
都已经通过\
进行转义,把元字符变为字面值\t
制表符 (‘\u0009’)\n
新行(换行)符 (‘\u000A’)\r
回车符 (‘\u000D’)\f
换页符 (‘\u000C’)\a
报警 (bell) 符 (‘\u0007’)\e
转义符 (‘\u001B’)\\
反斜线字符x
字符 x
字符类
字符类 是字符在方括号[ ]
中的集合,表示“找到集合里任意一个字符”。
存在一些字符,在[ ]中和外面,有的含义是不一样的,有的含义一致。
- 比如,
.
表示匹配任意字符,[.]
表示匹配字面值.
[a-z]
表示匹配a-z
范围中任意字符,a
表示匹配a
a|b
表示匹配a
或者b
,[a|b]
表示匹配字符a
,字符|
,字符b
常用字符类表
字符类 | 说明 |
---|---|
[abc] |
a、b 或 c(简单类) |
[^abc] |
任何字符,除了 a、b 或 c(否定),其中^ 表示否定,通过\^ 可转义成字面值,如[^\^] 表示找到除了插入符外的任意字符。 |
[a-zA-Z] |
a 到 z 或 A 到 Z,两头的字母包括在内(范围) |
[a-d[m-p]] |
a 到 d 或 m 到 p:[a-dm-p](并集) |
[a-z&&[^bc]] |
a 到 z,除了 b 和 c:[ad-z](减去) |
[a-z&&[^m-p]] |
a 到 z,而非 m 到 p:[a-lq-z](减去) |
[0-9.,] |
匹配一个数字或者一个句点或者一个逗号 |
[0-9a-fA-F] |
匹配一位十六进制数 |
[a-zA-Z0-9\-] |
匹配一个字母数字字符或连字符 |
[0-9] |
表示匹配0-9中的一个数字,但是[1-31] 并不是匹配1-31之间的数字,而是1或2或3,当成了[1-3][1] |
预定义字符类
用一些元字符来预先定义字符的范围。常见的对应关系:
预定义字符 | 说明 |
---|---|
\d |
数字:[0-9] |
\D |
非数字: [^0-9] |
\w |
单词字符:[a-zA-Z_0-9] ,字母 或 数字 或 下划线 |
\W |
非单词字符:[^\w] |
\s |
空白字符:[ \t\n\x0B\f\r] 空格,tab,回车或者换行等 |
\S |
非空白字符:[^\s] |
乘法器
可以在一个字面值或者字符类后跟着一个大括号来使用乘法器。常见用法:
表达式 | 说明 |
---|---|
X{n} |
X,恰好 n 次 |
X{n,} |
X,至少 n 次 |
X{n,m} |
X,至少 n 次,但是不超过 m 次 |
X? |
X,一次或一次也没有,相当于X{0,1} |
X* |
X,零次或多次,相当于X{0,} |
X+ |
X,一次或多次 ,相当于X{1,} |
注意:表格中出现的{,},?,+,等符号,放在[ ]中,就变为了字面值[{}+?],{}+\?也都变为字面值了。
惰性Non-greedy,勉强Reluctant
乘法器可通过追加问号?来实现惰性。这里对优先顺序进行了反转,优先匹配字符少的。示例:
\d{4,5}?
表示“匹配\d\d\d\d
或\d\d\d\d\d
”。其实跟\d{4}
行为一致。".*?"
表示“匹配一个双引号,跟着一个尽可能少的字符,再跟着一个双引号”。
常见用法
表达式 | 说明 |
---|---|
X{n}? |
X,恰好 n 次 |
X{n,}? |
X,至少 n 次 |
X{n,m}? |
X,至少 n 次,但是不超过 m 次 |
X?? |
X,一次或一次也没有,相当于X{0,1} |
X*? |
X,零次或多次,相当于X{0,} |
X+? |
X,一次或多次 ,相当于X{1,} |
逻辑运算
主要分类
XY
表示X 后跟 YX|Y
表示 X 或 Y ,分支,你可以使用管道符号来实现匹配多种选择(X)
表示X,作为捕获组。
X|Y
cat|dog
表示“匹配cat或dog”。red|blue|
和red||blue
以及|red|blue
都是同样的意思,“匹配red或blue或空字符串”a|b|c
跟[abc]
一样- cat|dog|\ |表示“匹配
cat
或dog
或|
符号”。其中 \ | 被转义了,|
属于字面字符。 [cat|dog]
表示“找到a或c或d或d或g或o或t或一个管道符号|”.
(X)
- 在一周中找到一天,使用
(Mon|Tues|Wednes|Thurs|Fri|Satur|Sun)day
\(\)
表示“匹配一个左圆括号后,再匹配一个右圆括号”[()]
表示“匹配一个左圆括号或一个右圆括号”(red|blue)?
等同于(red|blue|)
\w+(\s+\w+)*
代表“找到一个或多个单词,它们以空格隔开”- 主要用途:括号是用来表示组的,也可以用来捕获子串。
捕获组:可以拥有多个捕获组,它们甚至可以嵌套使用。捕获组从左到右进行编号。只要计算左圆括号。
示例1:
(\w+) had a ((\w+) \w+)
,从左往右的话,共3个组,分别为(\w+)
、((\w+) \w+)
和(\w+)
。 代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21regex="(\\w+) had a ((\\w+) \\w+)";
str="I had a nice day";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);
System.out.println(matcher.matches());
System.out.println(matcher.groupCount());//返回组的总数
System.out.println(matcher.group(0));//表示完整匹配
System.out.println(matcher.group(1));//匹配(\\w+)
System.out.println(matcher.group(2));//匹配((\\w+) \\w+)
System.out.println(matcher.group(3));//匹配(\\w+)
//System.out.println(matcher.group(4));
//结果
true
//从一个成功返回的匹配中捕获组数量总是等于原来正则表达式中捕获组的数量
3
I had a nice day
I
nice day
nice示例2:正则表达式((cat)|dog)表示“匹配cat或dog”。这里总是存在两组捕获组。如果我们的输入文本是dog,那么捕获组1是dog,捕获组2是空字符串,因为另一个选择未被使用。代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16regex="((cat)|dog)";
str="dog";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);
System.out.println(matcher.matches());
System.out.println(matcher.groupCount());//返回组的总数
//System.out.println(matcher.group(0));//表示完整匹配
System.out.println(matcher.group(1));//匹配(\\w+)
System.out.println(matcher.group(2));//匹配((\\w+) \\w+)
//结果
true
2
dog
null替换
一旦你用了正则表达式来查找字符串,你可以指定另一个字符串来替换它。第二个字符串时替换表达式。你尝试去用ISO 8691格式的日期(YYYY-MM-DD)去替换美式日期(MM/DD/YY)- 通过正则表达式
(\d\d)/(\d\d)/(\d\d)
开始。注意这里有三个捕获组:月,日和两个数字表示的年。通过使用一一个反斜和一个捕获组号来引用一个捕获组。所以,你的替换表达式为20\3-\1-\2
。\3
表示引用YY
,\1
表示引用MM
,\2
表示引用DD
。 - 代码(调试中?)
- 通过正则表达式
向后引用
([abc])\1
表示“匹配aa或bb或cc”。其中\1
表示引用第一个捕获组号,如果捕获组中匹配的是a,那么\1
就表示a。代码示例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19regex="([abc])([cd])\\1\\2";
str="cdcd";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);
if(matcher.matches()) {
//一定要先执行匹配成功了,才能统计下面的组
System.out.println(matcher.matches());
System.out.println(matcher.groupCount());
System.out.println(matcher.group(1));
System.out.println(matcher.group(2));
//System.out.println(matcher.group(3));
//结果
true
2
c
d
}
边界匹配器
分类
符号 | 说明 |
---|---|
^ |
行的开头,行头 |
$ |
行的结尾,行尾 |
\b |
单词边界 |
\B |
非单词边界 |
\A |
输入的开头 |
\G |
上一个匹配的结尾 |
\Z |
输入的结尾,仅用于最后的结束符(如果有的话) |
\z |
输入的结尾 |
单词 边界
- 单词边界是 一个单词字符和非单词字符 之间的位置。
- 单词边界不是字符。它们宽度为零。
- 输入的文本it’s a cat有八个单词边界。如果我们在cat后追加一个空格,这里就会有九个单词边界。
\b\w\w\w\b
表示“匹配一个三个字母的单词”。
行 边界
- 每一块文本会分解成一个或多个行,用换行符分隔。
- 像单词边界一样,行边界也不是字符。它们宽度为零。
- 文本不是以换行符结束,而是以行结束。然而,任何行,包括最后一行,可以包含零个字符。
- 行头位置 是在一个换行符和下一行的第一个字符之间。与单词边界一样,在文本的开头也算作一个起始的行。
- 行尾位置 是在行的最后一个字符和换行符之间。与单词边界一样,文本结束也算作行结束。
- 用法:
^$
表示“匹配空行”。^.*$
将会匹配整个文本,因为换行符是一个字符,所以.
会匹配它。为了匹配单行,要使用惰性乘法器,^.*?$
。\^\$
表示“匹配尖符号后跟着一个美元符号”[$]
表示“匹配一个美元符”。然而,[^]
是非法单正则表达式。要记住的是尖符号在方括号中时有不同的特殊含义。把尖符号放在字符类中,这么用[\^]
。
文本 边界
- 从“行开始”和“行结束”变成“文本开始”和“文本结束”。
- 元字符
\A
和\z