本笔记来自 计算机程序的思维逻辑 系列文章
语法
单个字符
- 特殊字符
\t
\n
\r
- 八进制
\0
- 十六进制
\x
- Unicode编码字符
\u
- 斜杠
\\
- 元字符
.
*
+
()
?
$
[]
-
|
匹配其本身,需要加转义字符
字符组
任意字符
点号字符 .
,是元字符,默认模式下,它匹配除了换行符以外的任意字符
指定的多个字符之一
中括号 []
,匹配组中的任意一个字符
字符区间
字符组 []
中使用连字符 -
,表示连续的多个字符
排除型字符组
在字符组的最前面加字符 ^
字符组内的元字符
在字符组中,除了-^[]\
外,其它元字符不再具备特殊含义
字符组运算
多个字符组等同于并集,使用&&
表示交集
比如
[[abc][def]]
,等同于[abcdef]
比如
[a-z&&[^de]]
,匹配除了d
和e
外,a-z
的字符
预定义的字符组
-
\d
匹配一个数字字符,等同于[0-9]
-
\w
匹配一个单词字符,等同于[a-zA-Z0-9]
-
\s
匹配一个空白字符,等同于[\t\n\x0B\f\r]
-
\D
匹配一个非数字字符,即[^\d]
-
\W
匹配一个非单词字符,即[^\w]
-
\S
匹配一个非空白字符,即[^\s]
POSIX字符组
-
\p{Lower}
小写字母,等同于[a-z]
-
\p{Upper}
大写字母,等同于[A-Z]
-
\p{Digit}
数字,等同于[0-9]
-
\p{Punct}
标点符号,匹配!"#$%&'()*+,-./:;<=>?@[\]^_\``{|}~
中的一个
量词
常用量词
-
+
表示前面字符出现一次或多次比如
ab+c
,匹配abc
abbc
-
*
表示前面字符出现零次或多次比如
ab*c
,匹配ac
abc
abbbc
-
?
表示前面字符可能出现,也可能不出现比如
ab?c
,匹配ac
和abc
通用量词
语法 {m,n}
,出现次数从 m 到 n ,包括 m 和 n
如果 n 没有限制,可以省略
如果两者一样,可以写成 {m}
比如
goo{1,}gle
,匹配goooogle
gooooooogle
贪婪与懒惰
关于量词,它们的默认匹配是贪婪的
比如使用正则表达式
<a>.*</a>
,处理字符串<a>first</a><a>second</a>
时
本来想得到2个匹配:<a>first</a>
和<a>second</a>
但默认情况下只得到一个匹配,匹配所有内容
如果希望在碰到第一个匹配时就停止,应该使用懒惰量词,在量词后面加上符号?
即<a>.*?</a>
分组
表达式可以用括号()
括起来,表示一个分组,分组可以嵌套
捕获分组
分组默认都有一个编号,按照括号的出现顺序,从 1 开始,从左到右依次递增
比如
a(bc)((de)(fg))
分组0是整个字符串,分组1是bc,分组2是defg,分组3是de,分组4是fg
分组量词
可以对分组使用量词,表示分组的出现次数
比如
a(bc)+d
,表示bc
出现一次或多次
分组多选
括号()
和元字符|
一起,可以表示匹配其中的一个子表达式
比如
(http|ftp|file)
,匹配http
或ftp
或file
回溯引用
可以用斜杠\
加分组编号引用之前匹配的分组
比如
<(\w+)>(.*)</\1>
,匹配<title>Home</title>
命名分组
命名语法 (?<name>X)
,引用语法 \k<name>
比如
<(?<tag>\w+)>(.*)</\k<tag>>
匹配<title>Home</title>
非捕获分组
语法 (?:...)
,表示分组后续不需要被引用,提高性能
比如
(?:abc|def)
匹配模式
-
(?s)
单行模式 -
(?m)
多行模式 -
(?i)
不区分大小写模式
特殊边界
-
^
匹配整个字符串的开始;多行模式下,匹配行的开始比如
^abc
,表示整个字符串必须以abc
开始 -
$
匹配整个字符串的结束;多行模式下,匹配行的结束比如
abc$
,表示整个字符串必须以abc
结束 -
\A
不管任何模式,总是匹配整个字符串的开始边界 -
\Z
不管任何模式,总是匹配整个字符串,换行符之前的结束边界 -
\z
不管任何模式,总是匹配整个字符串的结束边界 -
\b
匹配单词边界
环视边界匹配
环视不是分组,不占用分组编号,也称为 断言
-
肯定顺序环视
(?=...)
要求右边的字符串匹配指定的表达式
-
否定顺序环视
(?!...)
要求右边的字符串不能匹配指定的表达式
-
肯定逆序环视
(?<=...)
要求左边的字符串匹配指定的表达式
-
否定逆序环视
(?<!...)
要求左边的字符串不能匹配指定的表达式
强制转义
语法 \Q...\E
,\Q
和 \E
之间的所有字符都会被视为普通字符
转义符
\
是一个元字符,要在正则表达式中表示其本身,需要使用它转义,即\\
在Java中,使用字符串表示正则表达式,而在字符串中,\
也是一个元字符,也就需要使用两个\
来表示,即\\
,如果要匹配其本身,则需要使用四个\
,即\\\\
Java API
Pattern
字符串表示的正则表达式可以被编译为一个Pattern
对象
编译有一定的成本,而且Pattern
对象只与正则表达式有关,与要处理的具体文本无关吗,它可以安全地被多线程共享,所以,在使用同一个正则表达式处理多个文本时,应该尽量重用同一个Pattern
对象,避免重复编译
匹配模式
-
Pattern.DOTALL
单行模式 -
Pattern.MULTILINE
多行模式 -
Pattern.CASE_INSENSITIVE
不区分大小写模式 -
Pattern.LITERAL
将其中的元字符看作普通字符static String quote(String s)
目的类似,将 s 中的字符都看作普通字符
切分
字符串中的 String[] split(String regex)
方法
split
将参数regex
看作正则表达式,而不是普通的字符,如果分隔符是元字符,就需要转义
split
的额外参数limit
,用于限定切分的数目
split 区别
-
Pattern
接受的参数是CharSequence
,更为通用 - 如果
regex
长度大于1或包含元字符,String
的split
方法会先将regex
编译为Pattern
对象,再调用Pattern
对象的split
方法,这时,为避免重复编译,应该优先采用Pattern
的方法 - 如果
regex
就是一个字符且不是元字符,String
的split
方法会采用更为简单高效的实现,这时,应该优先采用String
的方法
验证
字符串中的 boolean matches(String regex)
方法
实际调用Pattern
的静态方法 static boolean matches(String regex, CharSequence input)
实际过程:先将regex
编译成Pettern
对象,再调用Pattern
的matcher
方法生成一个Matcher
对象,最后调用Matcher
的matches
方法,判断是否完整匹配
Matcher
查找
-
boolean find()
遍历 -
String group()
匹配到的完整字符串 -
int start()
子字符串在整个字符串中的起始位置 -
int end()
子字符串在整个字符串中的结束位置加 1 -
int groupCount()
返回分组个数 -
String group(int group)
分组编号为 group 的内容 -
String group(String name)
分组命名为 name 的内容 -
int start(int group)
分组编号为 group 的起始位置 -
int end(int group)
分组编号为 group 的结束位置加 1
替换
字符串中的方法
String replace(char oldChar, char newChar)
String replace(CharSequence target, CharSequence replacement)
String replaceAll(String regex, String replacement)
String replaceFirst(String regex, String replacement)
后3个方法实际调用Pattern
的compile
matcher
方法和Matcher
的replaceAll
replaceFirst
方法
边查找边替换
-
Matcher appendReplacement(StringBuffer sb, String replacement)
将匹配到的子字符串替换成 replacement 后追加到 sb 后,并更新最后追加位置 -
StringBuffer appendTail(StringBuffer sb)
将最后追加位置之后的子字符串追加到 sb 后
网友评论