本笔记来自 计算机程序的思维逻辑 系列文章
语法
单个字符
- 特殊字符
\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,匹配abcabbc -
*表示前面字符出现零次或多次比如
ab*c,匹配acabcabbbc -
?表示前面字符可能出现,也可能不出现比如
ab?c,匹配ac和abc
通用量词
语法 {m,n} ,出现次数从 m 到 n ,包括 m 和 n
如果 n 没有限制,可以省略
如果两者一样,可以写成 {m}
比如
goo{1,}gle,匹配gooooglegooooooogle
贪婪与懒惰
关于量词,它们的默认匹配是贪婪的
比如使用正则表达式
<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 后