1、String对正则表达式的支持
正则表达式就是用于匹配字符串的模板,使用它可以对字符串进行查找、替换、分割、提取等操作,String的以下几个方法就依赖java的正则表达式。
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为分隔符分割字符串,比如 "c++, java, c#".split(", "),"ab1cd2ef3g".split([123])表示以"1"或"2"或"3"分割字符串。
2、创建正则表达式字符串
正则表达式中包括两种字符,“字面意义字符”和“元字符”,字面意义字符就是按照字面意义比较,如"前面String.split()示例中的","。元字符为特色字符、通配符等,如“^”、“|”等,如"^abc"表示匹配行首出现abc的情况,“A|B”表示字符A或者B。
如果要匹配元字符本身的话应该加上\,比如要匹配字符^则使用\^,匹配字符$则使用\$,匹配字符\则使用\\,如果不清楚哪些标点符号为元字符,可以在比较的时候都加上\,比如逗号不是元字符,也可以使用\,来匹配。在Java中使用字符串撰写正则表达式的时候,先写下正则表达式内容,然后需要在每个"\"前再加一个"\",如:"ab\ncd\nef".split("\\n")表示以换行符分割字符串,"a|b|c".split("\\|")表示以"|"分割字符串,"a||b||c".split("\\|\\|")表示以"||"分割字符串。字符串"a\\b\\c"实际上表示的文本是"a\b\c",所以"a\\b\\c".split("\\\\")表示的是以一个反斜杠来分割字符串。
正则表达式支持的合法字符(字面意义字符):
String str = "A";
str.matches("A"); //true
str = "B";
str.matches("A"); //false
str = "A\n";
System.out.println(str.matches("\\x41\\n")); //true
str = "a\t";
str.matches("\\u0061\\t"); //true
正则表达式的特殊字符:
圆括号用来分组,将多个表达式组成一个表达式,圆括号之间可以使用或运算| 。
str = "c99";
str.matches("[abcd]99"); //true
str = "A\\"; //str实际为"A\"
str.matches("\u0041\\\\"); //true
str = "*$";
str.matches("\\*\\$"); //true
str = "protected";
str.matches("(public)|(protected)|(private)"); //true
boolean b = "milanleon2019@".matches("^[a-zA-Z]+\\d*@"); //true, 字符串的开头字符为字母,结尾的@之前可以为数字
b = "126mail.".matches("[a-zA-Z0-9]+\\."); //true, 结尾的.之前可以为字母或数字
b = "milanleon2019@126mail.com".matches("^[a-zA-Z]+\\d*@[a-zA-Z0-9]+\\.com"); //true, 邮箱的正则验证
b = "milanleon2019@126mail.163mail.com".matches("^[a-zA-Z]+\\d*@([a-zA-Z0-9]+\\.)+com"); //true, 复杂邮箱的正则验证
正则表达式的通配符(预定义字符):
str = "cat";
str.matches("c\\wt"); //true
str = "123-766";
str.matches("\\d\\d\\d-\\d\\d\\d"); //true
"12abcfoo".matches(".*foo"); //true,以foo结尾的字符串都符合正则
方括号可以用来匹配范围:
str = "c99";
str.matches("[abcd]99"); //true
str = "2end";
str.matches("[1-3]end"); //true
str = "1test";
str.matches("[1-3a-d]test"); // true
str.matches("[^123]test"); //false
边界匹配符:
String[] ary = "my dog doggie".split("\\bdog\\b"); //ary中为"my "、" doggie",使用单词标记\b的话就不会将doggie中dog作为分隔符
还可以对表达式出现的次数进行控制筛选,称为“贪婪量词”(贪婪模式):
除了“贪婪量词”外,还有“逐步量词”,“独吐量词”,在贪婪量词后加上"?"会成为逐步量词(勉强模式),在贪婪量词后加上"+"会成为独吐量词(占用模式),独吐量词只在JAVA上使用,一般很少使用:
String str = "0311-88062655";
str.matches("\\d{4}-\\d{8}"); //true
str = "hello, java!";
//String.replaceFirst(): 将符合正则的部分替换成指定字符串,找到第一个符合的就停止
String s1 = str.replaceFirst("\\w+", "hi"); //s1为"hi, java",找到的符合贪婪模式正则的字符串为"hello"(hello符合字母出现多次),替换它为"hi"
s1 = str.replaceFirst("\\w+?", "H"); //s1为"Hello, java", 找到的符合逐步模式正则的字符串为"h"(h符合字母出现一次),替换它为"H"
//String.replaceFirst(): 将符合正则的部分替换成指定字符串,找到所有符合的字符串进行替换
str = "xfooxxxxfoo".replaceAll(".*foo", "orz");//str为"orz",找到的符合贪婪模式正则的字符串为"xfooxxxxfoo"(前面的xfooxxxx符合正则.*),即整个字符串,所以将整个字符串替换为"orz"
str = "xfooxxxxfoo".replaceAll(".*?foo", "orz");//str为"orzorz",找到的符合逐步模式正则的字符串为"xfoo"和"xxxxfoo"(前面的xfoo符合正则.*foo,后面的xxxxfoo也符合正则.*foo),所以将两处替换为"orz"
3、Pattern和Matcher
除了String中的matches()、split()、replaceXXX()等方法,java还提供了Pattern和Matcher两个类用于支持正则表达式。Pattern的类方法matches()类似String的成员方法matches(),适合只使用一次正则表达式的情况。如果程序中需要多次使用某个正则的话,那么应该为该正则生成一个Pattern对象来使用,以提高效率。Pattern对象通过Pattern的类方法compile()来生成,其可以多次重复使用,而且它是线程安全的。
import java.util.regex.*;
public class Main {
public static void main(String[] args)
{
boolean b = Pattern.matches("a*b", "aaab"); //true
Pattern p = Pattern.compile("a*b"); //生成Pattern对象,使用正则表达式字符串来初始化它
//多次使用该正则:
Matcher m = p.matcher("aaab"); //生成Matcher对象,使用目标字符串来初始化它
b = m.matches(); //true, 通过Matcher对象来判断目标字符串是否与Pattern匹配
b = p.matcher("ab").matches(); //true
b = p.matcher("b").matches(); //true
Pattern p2 = Pattern.compile("\\*");
String[] ary = p.split("a*b*c");
}
}
Pattern的compile()方法还支持标志,如下所示:
Pattern p = Pattern.compile(".*foo", Pattern.CASE_INSENSITIVE); //不区分大小写
//Pattern p = Pattern.compile("(?i).*foo"); //与上面语句等效
boolean b = p.matcher("123Foo").matches(); //true
System.out.println(b);
Mather中除了使用 matches()来判断整个目标字符串是否匹配正则外,还有find()方法可以在整个目标字符串中查找符合正则的子串,replaceXXX()将目标字符串中符合正则的子串替换成指定的字符串:
find():判断目标字符串是否包含与Pattern匹配的子串。
group():返回上一次匹配到的子串,如上次find()匹配的子串。
replaceAll():将目标字符串中所有与正则表达式Pattern匹配的子串替换成指定字符串。
replaceFirst():将目标字符串中第一个与正则表达式Pattern匹配的子串替换成指定字符串。
replaceEnd():将目标字符串中最后一个与正则表达式Pattern匹配的子串替换成指定字符串。
reset():将Mather应用于一个新的目标字符串。
String str = "联系方式1:13500617745";
Matcher m = Pattern.compile("(13|15)\\d{9}").matcher(str); //13或15开头的11位数字(电话号码)
if(m.find()) //find()在目标字符串中查找到符合正则的子串就返回
{
String str = m.group(); //13500617745,获得前面find()匹配到的子串
}
String str = "联系方式1:13500617745,联系方式2:17951777117,联系方式3:15611114098";
Matcher m = Pattern.compile("(13|15)\\d{9}").matcher(str); //只提取13开头和15开头的手机号
while(m.find()) //find()会依次向下查找,还可以传入一个int参数以指定查找开始位置
{
System.out.println(m.group()); //输出前面find()匹配到的子串
}
//程序输出:
// 13500617745
// 15611114098
Pattern p = Pattern.compile("re\\w*");
Matcher m = p.matcher("java presses");
String str = m.replaceAll("测试"); // "java p测试“
Pattern p = Pattern.compile("re\\w*");
String[] msg = {"expressions in 1.4", "regular expressions now", "java presses"};
Matcher m = null;
//以下将String数组中元素作为正则的目标字符串来依次处理
for(int i = 0; i < msg.length; i++)
{
if(m == null)
{
m = p.matcher(msg[i]);
}
else
{
m.reset(msg[i]);
}
System.out.println(m.replaceAll("测试"));
}
//输出为:
//exp测试 in 1.4
//测试 exp测试 now
//java p测试
Mather中的其它方法:
start():返回上一次匹配到的子串的开始位置,即符合字符串的起始索引。
end():返回上一次匹配到的子串的结束位置+1,即符合字符串最后一个字符后的索引。
lookingAt():判断目标字符串前面部分是否与Pattern匹配。
在使用replaceAll()时,如果正则中有使用括号分组,那么可以使用$来代表目标字符串中分组匹配的文字:
Pattern p = Pattern.compile("(^[a-z].*)@([A-Z].*).com");
String s = p.matcher("leon@ADA.com").replaceAll("$1@$2.cc"); // "leon@ADA.cc"