规则表达式包括两种字符:字面意义字符与元字符
- 字面意义字符:按照字面意义比较的字符
- 元字符:不按照字面比较,在不同情境有不同意义的字符
字面意义字符
字母和数字在规则表达式中,都是按照字面意义比较,有些字符前加了\之后,会被当作元字符。
XY —— X之后要跟随着Y
X|Y —— X或Y
[XYZ] —— X或Y或Z
元字符如! $ ^ * ( ) + = { } [ ] | \ : . ?等在规则表达式中有特殊意义,若要比较这些字符,则必须加上忽略符号\
举个栗子,想要将”aaa+bbb+ccc”用split()按+切割,要使用的规则表达式是+,要将其放在”“之间时,按照Java字符串的规定,必忽略+的\,所以撰写为”\+”
“aaa||bbb||ccc”,规则表达式||,撰写为Java字符串是\+\+
“aaa\bbb\ccc” ,规则表达式\,撰写为Java字符串是\\
规则表达式是规则表达式,在Java中将其撰写在”“中又是另一回事,不能混为一谈。
字符类
规则表达式中多个字符可以分归在一起成为一个字符类,字符类会比较文字中是否有“任一个”字符符合字符类中某个字符。归类字符的方式之一是将字符放于[]之中。
[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&&[def]] —— a到z并且是def任一字符,相当于[def]
[a-z&&[^bc]] —— a到z并且是bc以外的任一字符,相当于[ab-z]
[a-z&&[^m-p]] —— a到z并且是m-p以外的任一字符,相当于[a-lq-z]
预定义字符类
. —— 任一字符
\d —— [0-9]
\D —— [^0-9]
\s —— 任一空格符,即[\t\n\x0B\f\r]
\S —— 任一非空格符,即[^\s]
\w —— 任一ASCII字符,即[a-zA-Z0-9]
\W —— 任一非ASCII字符,即[^\w]
贪婪、逐步、独吐量词
如果想让用户输入的手机号码 格式为xxxx-xxxxxx,x为数字,规则表达式可使用\d\d\d\d-\d\d\d\d\d\d,还有更简单的写法是\d{4}-\d{6}
{n}是贪婪量词表示法的一种,表示前面的项目出现n次
X? —— X项目出现一次或没有
X* —— X项目出现零次或多次
X+ —— X项目出现一次或多次
X{n} —— X项目出现n次
X{n,} —— X项目至少出现n次
X{n,m} —— X项目出现n次但不超过m次
贪婪的意思是,比较器在看到贪婪量词时,会把剩余文字整个吃掉,再逐步吐出文字,看看是否符合贪婪量词后的规则表达式。如果吐出部分符合,而吃下部分也符合贪婪量词就比较成功,结果就是贪婪量词会尽可能找出长度最长的符合文字。
例如,xfooxxxxxxfoo,若使用规则表达式.*foo
比较,比较器会先吃掉整个xfooxxxxxxfoo,再吐出foo符合foo部分,剩下xfooxxxxxx也符合.*
部分,所有得到的符合字符串就是整个xfooxxxxxxfoo
如果在贪婪量词表示法后加上?,将会成为逐步量词,又称为懒惰量词,或非贪婪量词,比较器看到逐步量词,会一边吃掉剩余文字,一边看看吃下的文字是否符合规则表达式,结果就是逐步量词会尽可能找出长度最短的符合文字。
例如,xfooxxxxxxfoo,若使用规则表达式.*?foo
比较,比较器在吃掉xfoo后发现符合*?foo,接着继续吃掉xxxxxxfoo发现符合,所以得到xfoo与xxxxxxfoo两个符合文字。
如果在贪婪量词表示法后加上+,将会成为独吐量词,比较器看到独吐量词,会先将剩余文字吃掉,看看独吐量词部分是否符合吃下的文字,如果符合就不会再吐出来了。
例如,xfooxxxxxxfoo,若使用规则表达式.*+foo
比较,比较器会先吃掉整个xfooxxxxxxfoo,结果.*+
就可以符合了xfooxxxxxxfoo了,所以比较器就不会再吐出文字,因为没有剩余文字符合foo部分,所以结果就是没有任何文字符合。
边界比较
先看一个程序:
public class SplitDemo2 {
public static void main(String[] args) {
for(String str : "Justin dog Monica doggie Irene".split("dog")) {
System.out.println(str.trim());
}
}
}
我们想得到的一定是”Justin”与”Monica doggie Irene”两个部分,但是执行结果却是”Justin” “Monica” “gie Irene”,doggie因为当中有dog子字符串,也被切割。
可以使用\b标出单词边界,如\bdog\b,这就只会比较出dog单词。改为.split(“\bdog\b”)。
边界比较用来表示文字必须符合指定的边界条件,也就是定位点,因此这类表示式也常称为锚点。
^ —— 一行开头
$ —— 一行结尾
\b —— 单词边界
\B —— 非单词边界
\A —— 输入开头
\G —— 前一个符合项目结尾
\Z —— 非最后终端机的输入结尾
\z —— 输入结尾
分组与参考
可以使用()来将规则表达式分组,除了作为子规则表达式之外,还可以搭配量词使用。
例如想要验证电子邮件格式:
1. 允许的用户名称开头要是大小写英文字符,之后可搭配数字
可以这样表示^[a-zA-Z]+\d*;
2. 因为@后域名可以有数层,必须是大小写英文字符或数字
可以这样表示([a-zA-Z0-9]+.)+,其中使用了()群组了规则表达式,之后的+表示这个群组的表达式符合一次或多次
3. 最后要是com结尾,整个结合起来的规则表达式就是
^[a-zA-Z]+\d*@([a-zA-Z0-9]+.)+com
例,(\d\d)\1表示要输入4个数字,1212符合,1234不符合。\1要求接下来输入也要是前面输入的数字。
["'][^"']*["']
会比较单引号或双引号中0或多个字符
(["'])[^"']*\1
会比较前后引号必须一致。