最近做了一些爬虫匹配的东西,顺便复习了一下正则表达式。整理用java演示。
一、单个字符匹配
1、匹配任意字符
在这里我们用一个点来匹配任意字符也就是( . )
System.out.println("abc".matches("a.c"));
System.out.println("a$c".matches("a.c"));
System.out.println("acc".matches("a.c"));
这里的输出结果都是true。
2、匹配数字
这里用 \d 来匹配,其中上面\\d第一个斜杠是转义的意思表示\d。结果是上面是true,下面是false。
System.out.println("007".matches("00\\d"));
System.out.println("00a".matches("00\\d"));
3、匹配常用字符
这里的常用字符指的是一个字母、数字或者下划线。用\w表示,这里面都是true。
System.out.println("javac".matches("java\\w"));
System.out.println("java_".matches("java\\w"));
System.out.println("java1".matches("java\\w"));
4、匹配空格字符
用\s可以匹配一个空格字符,注意空格字符不但包括空格,还包括tab字符(在Java中用\t表示)
System.out.println("java ".matches("java\\s"));
5、匹配非数字
用\d可以匹配一个数字,而\D则匹配一个非数字。例如,00\D可以匹配。
匹配规则
正则表达式 |
规则 |
可以匹配 |
A |
指定字符 |
A |
\u548c |
指定Unicode字符 |
和 |
. |
任意字符 |
a,b,&,0 |
\d |
数字0~9 |
0~9 |
\w |
大小写字母,数字和下划线 |
a~z,A~Z,0~9,_ |
\s |
空格、Tab键 |
空格,Tab |
\D |
非数字 |
a,A,&,_,…… |
\W |
非\w |
&,@,中,…… |
\S |
非\s |
a,A,&,_,…… |
二、重复匹配
利用修饰符 * 可以匹配任意字符包括0个字符。
System.out.println("java".matches("java\\d*"));
System.out.println("java1".matches("java\\d*"));
System.out.println("java11".matches("java\\d*"));
System.out.println("java123".matches("java\\d*"));
上面都是true。
利用修饰符 + 可以至少匹配一个字符。
利用修饰符 ? 可以匹配0个或者一个字符。
精确的指定n个字符
System.out.println("java123".matches("java\\d{3}"));
System.out.println("java1".matches("java\\d{3}"));
匹配规则
正则表达式 |
规则 |
可以匹配 |
A* |
任意个数字符 |
空,A,AA,AAA,…… |
A+ |
至少1个字符 |
A,AA,AAA,…… |
A? |
0个或1个字符 |
空,A |
A{3} |
指定个数字符 |
AAA |
A{2,3} |
指定范围个数字符 |
AA,AAA |
A{2,} |
至少n个字符 |
AA,AAA,AAAA,…… |
A{0,3} |
最多n个字符 |
空,A,AA,AAA |
三、复杂匹配
(1)匹配开头和结尾
用 ^ 表示开头,$表示结尾。例如,^A\d{3}$,可以匹配"A001"、"A380"。
(2)匹配指定范围
使用[...]可以匹配范围内的字符,[123456789]\d{6,7},[1-9],[0-9a-fA-F],[^1-9]{3}
(3)或规则匹配
用|连接的两个正则规则是或规则,例如,AB|CD表示可以匹配AB或CD。
(4)使用括号
String re = "learn\\s(java|php|go)";
System.out.println("learn java".matches(re));
System.out.println("learn Java".matches(re));
System.out.println("learn php".matches(re));
System.out.println("learn Go".matches(re));
正则表达式 |
规则 |
可以匹配 |
^ |
开头 |
字符串开头 |
$ |
结尾 |
字符串结束 |
[ABC] |
[…]内任意字符 |
A,B,C |
[A-F0-9xy] |
指定范围的字符 |
A,……,F,0,……,9,x,y |
[^A-F] |
指定范围外的任意字符 |
非A~F |
AB|CD|EF |
AB或CD或EF |
AB,CD,EF |
四、分组匹配
分组匹配中非常重要的一点就是截取子串。
Pattern p = Pattern.compile("(\\d{3,4})\\-(\\d{7,8})");
Matcher m = p.matcher("010-12345678");
if (m.matches()) {
String g1 = m.group(1);
String g2 = m.group(2);
System.out.println(g1);
System.out.println(g2);
} else {
System.out.println("匹配失败!");
}
要特别注意,Matcher.group(index)方法的参数用1表示第一个子串,2表示第二个子串。如果我们传入0会得到什么呢?答案是010-12345678,即整个正则匹配到的字符串们在前面的代码中用到的正则表达式代码是String.matches()方法,而我们在分组提取的代码中用的是java.util.regex包里面的Pattern类和Matcher类。实际上这两种代码本质上是一样的,因为String.matches()方法内部调用的就是Pattern和Matcher类的方法。
但是反复使用String.matches()对同一个正则表达式进行多次匹配效率较低,因为每次都会创建出一样的Pattern对象。完全可以先创建出一个Pattern对象,然后反复使用,就可以实现编译一次,多次匹配:
Pattern pattern = Pattern.compile("(\\d{3,4})\\-(\\d{7,8})");
pattern.matcher("010-12345678").matches(); // true
pattern.matcher("021-123456").matches(); // true
pattern.matcher("022#1234567").matches(); // false
// 获得Matcher对象:
Matcher matcher = pattern.matcher("010-12345678");
if (matcher.matches()) {
String whole = matcher.group(0); // "010-12345678", 0表示匹配的整个字符串
String area = matcher.group(1); // "010", 1表示匹配的第1个子串
String tel = matcher.group(2); // "12345678", 2表示匹配的第2个子串
System.out.println(area);
System.out.println(tel);
}
非贪婪匹配:
例如匹配1230000字符串,我想截取前面123和后面都是0的两段子串:
如果用"(\\d+)(0*)"去匹配就会在\d的时候匹配完1230000全都匹配,导致后面的子串是“”。这就是贪婪匹配。利用+?可以完成非贪婪匹配。
Pattern pattern = Pattern.compile("(\\d+?)(0*)");
Matcher matcher = pattern.matcher("1230000");
if (matcher.matches()) {
System.out.println("group1=" + matcher.group(1)); // "123"
System.out.println("group2=" + matcher.group(2)); // "0000"
}
五、搜索和替换
正则表达式也可以完成字符串的匹配和替换。
(1)分割字符串
"a b c".split("\\s"); // { "a", "b", "c" }
"a b c".split("\\s"); // { "a", "b", "", "c" }
"a, b ;; c".split("[\\,\\;\\s]+"); // { "a", "b", "c" }
(2)搜索字符串
String s = "the quick brown fox jumps over the lazy dog.";
Pattern p = Pattern.compile("\\wo\\w");
Matcher m = p.matcher(s);
while (m.find()) {
String sub = s.substring(m.start(), m.end());
System.out.println(sub);
}
(3)替换字符串
String s = "The quick\t\t brown fox jumps over the lazy dog.";
String r = s.replaceAll("\\s+", " ");
System.out.println(r); // "The quick brown fox jumps over the lazy dog."
(4)反向引用
String s = "the quick brown fox jumps over the lazy dog.";
String r = s.replaceAll("\\s([a-z]{4})\\s", " <b>$1</b> ");
System.out.println(r);