初识正则
正则表达式是一些用来匹配
(搜索)和处理
(替换)文本的字符串。
正则表达式是文本处理的强大工具,作用对象是文本/字符串。
具体到某一个正则表达式,也称为模式
(Pattern),模式由字面量(可由十六进制表示\x开头或八进制表示\0开头),元字符(. \ [等)或两者组合而成。
有特殊含义的字符要加反斜杠 \ 转义。\ 本身也是一个元字符(不表示其本身含义而具有特殊含义的字符)。
元字符
有两类:一类用于匹配文本(.*+等),另一类是正则表达式语法所要求的,如\ [等。
用法大全
匹配任意字符
.
英文句号,可以匹配除换行符以外的任意单个字符
匹配一组字符
[]
定义一个字符集合/字符类,匹配的结果是与任意一个集合成员相匹配的字符
- 常用于局部不需要区分大小写的情形,如
[Cc]hang
- 字符集合中的有些元字符不需要转义(如.+),当然转义也没有错:
[\w.]
和[\w\.]
等效 - 字符集合中可以使用字符区间如0-9,a-z,A-Z,其中-(连字符)是一个定义字符区间的元字符。-并不需要转义,它仅在连接字符区间端点的时候有特殊含义,其他时候都是一个字面量,如
[0-9-]
- 字符区间的端点可以是ASCII字符表里的任意字符,但实际中最常用数字字符区间和字母字符区间
- A和a的ASCII码分别是65和97,而97-65=32(Z和a之间还有[\等6个符号),所以一般不用
[A-z]
这一字符区间。
取非匹配
^
用于 [ 和 ] 之间并且紧跟在 [ 后面,如[^abc]
表示除a,b,c之外的任意单个字符
字符集合的嵌套和运算
如[A-Za-z0-9]
, [a-z&&[^bc]]
,其中&&
为与操作符,另|
为或操作符(注意优先级)
特殊的字符类
1
2
3
4
5
6
7
8
9
10
11
\d<==>[0-9] 任何一个数字字符
\D<==>[^0-9] 任何一个非数字字符
\w<==>[0-9A-Z_a-z] 任何一个单词字符(大小写字母、数字、下划线)
\W<==>[^0-9A-Z_a-z]
\s<==>[\f\n\r\t\v] 任何一个空白字符(不包括退格符\b)
\S<==>[^\f\n\r\t\v]
POSIX字符类:
[[:lower:]]<==>[a-z] 匹配小写
[[:upper:]]<==>[A-Z] 匹配大写字母
[[:alpha:]]<==>[a-zA-Z] 匹配大小写字母
字符类\d,\w,\s等也是一种元字符,这里\其后的字母整体构成元字符
重复匹配
它们都是贪婪型的元字符,可能会导致过渡匹配,它们的懒惰型版本只用在其后多加一个问号?
如对于字符串”acbacb”,模式a.*b
匹配整个字符串,但a.*?b
仅与”acb”匹配
1
2
3
4
5
6
7
.
*
+
{ 重复次数 }
{3}
{0,3}
{3, }
位置匹配
使用边界限定符
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
\b 单词边界,匹配\w和\W之间的位置
如"I |am Cliu",所处的位置位于空格和a之间,与\b匹配
\b匹配单词的开头、结尾,要匹配整个单词,要在该单词前后都加上\b
\B 非单词边界。
如\B-\B匹配case - sensitive中前后有空格的连字符,因为空格和-都不和\w匹配
^ $ 字符串边界
^和$匹配字符串开头、结尾两个位置,而不是字符,相比于\b常用于字符串内/行内单词匹配,^和$常用来匹配一整行/一整个字符串
(?m)字符串分行匹配模式标志
置于整个模式的开头,可避免将一个含有多行的文件当作一个字符串匹配
(?i)模式不区分大小写标志
这两个标志的功能都可以通过Pattern中的常量(flags)来实现且性能可能更好:
对应MIULTILINE和CASE_INSENSITIVE
子表达式
( )
内的多个字符/表达式被当作一个整体来对待
可以用于控制优先级,设置一组字符的重复以及回溯引用(\1,\2 …相当于变量,其值为模式的第1,2个子表达式)
如m|food
匹配”m”或”food”,因为字符优先级高于|
运算符,(m|f)ood
才匹配”mood”或”food”
回溯引用指在模式的后半部分引用前半部分的定义的子表达式,用作模式内部引用,文本替换/重排等,如(pattern)\1
表示pattern连续出现两次
替换
回溯引用在查找和替换中分别写作\1
和$1
1
2
3
4
5
\E 结束\L或\U转换
\l 把下一个字符或子表达式转换为小写
\L 把\L后面的所有字符转换为小写,除非遇到\E
\u 把下一个字符或子表达式转换为大写
\U 把\U后面的所有字符转换为大写,除非遇到\E
前后查找
1
2
3
4
(?=regex) 向前查找
(?<=regex) 向后查找,regex必须是定长的,即不能包含* + {3, }等变长参数
(?!regex) 负向前查找(向前查找取非)
(?<!regex) 负向后查找(向后查找取非)
向前查找和向后查找,首先是一个子表达式
,指定那些要求匹配但不在结果中返回的模式(不捕获)
实质上向前查找指定了它前面的文本必须以regex结尾,向后查找指定了它后面的文本必须以regex开头,即匹配结果处于什么位置
在正则表达式中嵌入条件
1
(?(condition)X|Y) // 根据condition是否匹配到执行后续模式X或Y的匹配,|Y可省略
其中,(condition)
可以是表示回溯引用的数字(1),(2),(3)...
,也可以是表示前后查找匹配的(?=pattern)
等
应用
MySQl中的正则表达式
1
2
--MySQL的where子句对正则表达式提供了支持
select * from db where Sname REGEXP "liu?(先生|女士)"
MySQl中正则表达式搜索默认不区分大小写,如果要区分大小写,用 …Sname REGEXP BINARY “liu?(先生|女士)”
LIKE匹配整个列,而REGEXP只要有该子串匹配就返回该列,也可以使用^,$让正则表达式匹配整个列
MySQl使用两个反斜杠转义,如\n应转义为\n.,\应转义为\\,MySQL本身解释一个,正则表达式库解释另一个
可以使用类似select “Hello” REGEXP “.+”这样的语句测试正则表达式 字符类应采用POSIX字符类,如[[:lower:]]等
Java中的正则表达式
见java.util.regex.Pattern类:
典型用法
1
2
3
4
5
6
7
8
9
10
11
//将正则表达式编译为Pattern类实例,可重用,效率高
Pattern p = Pattern.compile("a*b",flags);
//由模式p创建Matcher类对象并与字符序列(参数)进行匹配
Matcher m = p.matcher("aaaaab");
//匹配结果都驻留在匹配器m中,可以执行三种匹配操作matches()、find()或lookingAt()
boolean b = m.matches();
//结果为true
Matcher m = Pattern.compile(“\\\\”).matcher(“\\”);
\\n和\n将被编译为相同的模式,因为java编译器和正则表达式解析器都认识\n(同样,它们还共同认识\u2014等unicode字符)。 Java 源代码的字符串中的反斜线被解释为 Unicode 转义或其他字符转义(valid escape sequences are \b \t \n \f \r \” \’ \\)。
于是Java编译器将”\n”中的第一个\连同其后的\理解成代表反斜杠的转义字符,于是传给正则表达式解析器的就是”\n”。 另一方面,Java编译器将”\n”解释成换行符传给正则表达式解析器,它当然也认识。
Kotlin中的正则表达式
见kotlin.text.Regex类
Kotlin中的三重引号字符串”"”pattern””“,指定的模式无需转义
常见问题的正则表达式解决方案
- IP地址
由4个字节组成,每个字节取值范围都是0~255,通常被写为4组以.分隔的整数(1~3位)1 2 3 4
//粗匹配 (\d{1,3}\.){3}\d{1,3} //准确匹配 (((\d{1,2}|(1\d{2})|(2[0-4]\d)|(25[0-5])))\.){3}((\d{1,2}|(1\d{2})|(2[0-4]\d)|(25[0-5])))
- URL地址
1
https?://[-\w.]+(:\d+)?(/([\w/_.]*)?)?
- 电子邮件地址
1
(\w+\.)*\w+@(\w+\.)+[[:alpha:]]+