正则表达式
正则表达式
Java提供了Pattern类和Matcher类支持正则表达式,除此之外String类的以下几个方法也支持正则表达式
boolean matches(String regex); // 判断该字符串是否匹配表达式regex
String replaceAll(String regex,String replacement); // 将所有匹配regex的字符串用replacement替换
String replaceFirst(String regex,String replacement);// 将第一个匹配regex的字符串用replacement替换
String[] split(String regex); // 以regex为分隔符,将字符串分隔为子串
正则表达式是一个用于匹配字符串的模板,可以匹配一批字符串,所以创建正则表达式就是创建一个特殊的字符串。
创建正则表达式
x 字符x,x可代表任何合法的字符
\0nnn 八进制数0nnn所表示的字符
\xhh 十六进制数0xhh表示的字符
\uhhhh 十六进制值0xhhhh表示的UNICODE字符
\t 制表符 \u0009
\n 换行 \u0000A
\r 回车 \u000D
\f 换页符 \u000C
\a 报警符 \u0007
\e Esc \u001B
\cx x对应的控制符
特殊字符
\\ 反斜线
$ 匹配一行结尾,要匹配$,使用\$
^ 匹配一行的开头,要匹配^,使用\^
() 标记子表达式的开始和结束位置,要匹配()时使用\(和\)
[] 用于确定中括号表达式的开始和结束位置,要匹配[]时使用\[和\]
{} 用于标记前面的子表达式的出现频度,要匹配{}时使用\{和\}
* 指定前面的子表达式可以出现零次或多次,要匹配*时使用\*
+ 指定前面子表达式可以出现一次或多次,要匹配+时使用\+
? 指定前面的子表达式可以出现零次或一次,要匹配时使用\?
. 匹配除换行符\n之外的任何字符,要匹配时使用\.
\ 用于转义下一个字符,或指定八进制或十六进制字符,要匹配时使用\\
| 指定两项之间任选一项.要匹配时使用\|
预定义字符
. 匹配任何字符
\d 数字(digit) 等价于[0-9]
\D 非数字 等价于[^0-9]
\s 空白符号(space) [\t\r\n\f空格]
\S 非空白符号
\w 单独字符(word) [a-zA-Z_0-9]
\W 非单独字符(26个字母大小写数字及下划线) [^a-zA-Z_0-9]
结合d-digit,s-space,w-word,大写是他们的相反的形式
方括号表达示
表示枚举,如[abc]表示a,b,c其中任意一个字符
表示范围(-),如[a-f]表示a~f内的任意字符,[\\u0041-\\u0056]表示十六进制字符\u0041到\u0056范围内的字符
范围可以组合,如[a-fA-F]表示a~f内的任意字符不分大小写.
表示求否^,如[^abc]表示a,b,c以外的任意字符,[^a-f]表示a~f以外的任意字符
表示与运算(&&),如[a-z&&[def]]表示a-z与[def]的交集,即a,ef
表示并运算,如[a-d[m-p]],表示[a-dm-p],即a~d或m~p中的任意字符
正则表达式还支持圆括号表达式,用于将多个表达式组成一个表达式,圆括号中可以使用|运算符.
如"(public|protected|private)"用于匹配java的三个访问控制符之一.
边界匹配符
^ 行的开头
$ 行的结尾
\A 输入的开头
\Z 输入结尾,公用于最后的结束符
\z 输入的结尾
\b 一个单词的边界
\B 一个非单词的边界
\G 前一个匹配的结束
数量标识符
贪婪模式 勉强模式 占用模式 说明
X? X?? X?+ X表达式出现0次或1次
X* X*? X*+ X表达式出现0次或多次
X+ X+? X++ X表达式出现1次或多次
X{n} X{n}? X{n}+ X表达式出现n次
X{n,} X{n,}? X{n,}+ X表达式最少出现n次
X{n,m} X{n,m}? X{n,m}+ X表达式最少出现n次,最多出现m次
使用正则表达式
使用Pattern和Matcher来使用正则表达式,Pattern对象是正则表达式编译后在内存中的表示形式,因此表达式字符串必须先被编译成Pattern对象,
然后再利用该对象创建对应的Matcher对象.执行匹配所涉及的状态保留在Matcher对象中,多个Matcher对象可共享一个Pattern对象.
Pattern p = Pattern.compile("a*b"); // 将一个字符串编译成Pattern对象
Matcher m = p.matcher("aaaaab"); // 使用Pattern对象创建Matcher对象
boolean b = m.matches(); // 返回结果 true
上面3行代码等效于:
boolean b = Pattern.matches("a*b", "aaaaab");
但采用这种形式每次都需要重新编译Pattern对象,不能复用已编译的Pattern对象,效率不高.
Pattern是不变类,可供多个并发线程安全使用.
static Pattern compile(String regex);
static Pattern compile(String regex, int flag);
flag参数:
Pattern.CANON_EQ
两个字符当且仅当它们的完全规范分解相匹配时,才是匹配的.
如,表达式a\u030A就会匹配字符串?
默认情况下不会考虑规范的等价性
Pattern.CASE_INSENSITIVE
大小写不敏感的匹配假定只有US-ASCII字符集中的字符才能进行.
这个模式匹配不必考虑大小写.
通过指定UNICODE_CASE标记及结合此标记,基于Unicode的大小写不敏感的匹配就可以开启了
可通过嵌入(?i)开启,如regex中增加(?i)
Pattern.COMMENTS
忽略空格.并且以#开始直到行末的注释也会被忽略掉
可通过嵌入(?x)开启Unix的行模式
Pattern.DOTALL
dotall模式中,"."匹配所有字符,包括行终结符.默认情况下,"."不匹配行终结符
可通过嵌入(?s)开启dotall模式
Pattern.MULTILINE
多行模式下,^和$分别匹配一行的开始和结束.^还匹配输入的字符串开始,而$还匹配输入的字符串的结尾.
默认情况下,这些表达式只匹配输入的完整字符串的开始和结束.
可通过嵌入(?m)开启
Pattern.UNICODE_CASE
指定这个标记并且开启CASE_INSENSITIVE时,大小写不敏感的匹配将按照与Unicode标准相一致的方式进行.
默认情况下是US-ASCII字符集中的字符才能进行大小写不敏感的匹配
可通过嵌入(?u)开启
Pattern.UNIX_LINES
在这种模式下,在.^$行为中,只识别行终结符\n
可通过嵌入(?d)开启
可以使用|操作符组合多个标记的功能.
Matcher类提供以下几个常用方法:
boolean find();
boolean find(int start); // 返回目标字符串中是否包含与Pattern匹配的子串
String group(); // 返回上一次匹配的子串
int start(); // 返回上一次与Pattern匹配的子串在目标字符中的开始位置
int end(); // 返回上一次与Pattern匹配的子串在目标字符串中的结束位置加1
boolean lookingAt(); // 返回目标字符串前面部分与Pattern是否匹配
boolean matches(); // 返回整个目标字符串与Pattern是否匹配
Matcher reset(CharSequence input); // 将现有的Matcher对象应用于一个新的字符序列
测试代码
Pattern pattern = Pattern.compile("a*b");
Matcher matcher = pattern.matcher("acdbab");
matcher.find();
Matcher m = Pattern.compile("\\w+").matcher("java is easy!");
while (m.find()) {
System.out.println(m.group());
}
int i = 0;
while (m.find(i)) {
System.out.println(m.group());
i++;
}
while (m.find()) {
System.out.println(m.group() + ", start=" + m.start() + ", end="
+ m.end());
}
String[] mail = { "baidu@126.com", "wawa@abc.xx", "aaa@lii.com@jj.org"};
String mailRegex = "\\w{3,20}@\\w+\\.(com|org|cn|net|gov)";
Pattern mailPattern = Pattern.compile(mailRegex);
Matcher matcher2 = null;
for (String string : mail) {
if (matcher2 == null) {
matcher2 = mailPattern.matcher(string);
} else {
matcher2.reset(string);
}
System.out.println(string + "是否匹配一个邮件地址?" + (matcher2.matches()));
System.out.println(string + " use lookingAt ?" + (matcher2.lookingAt()));
}
运行结果
java
is
easy
java
ava
va
a
is
is
s
easy
easy
asy
sy
y
java, start=0, end=4
is, start=5, end=7
easy, start=8, end=12
baidu@126.com是否匹配一个邮件地址?true
baidu@126.com use lookingAt ?true
wawa@abc.xx是否匹配一个邮件地址?false
wawa@abc.xx use lookingAt ?false
aaa@lii.com@jj.org是否匹配一个邮件地址?false
aaa@lii.com@jj.org use lookingAt ?true