正常匹配
public class Main {
public static void main(String[] args) {
Pattern pattern = Pattern.compile("(\\d{3,4})\\-(\\d{7,8})");
pattern.matcher("010-12345678").matches(); // true
pattern.matcher("021-123456").matches(); // false
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个子串
}
}
}
使用Matcher
时,必须首先调用matches()
判断是否匹配成功,匹配成功后,才能调用group()
提取子串。
普通捕获组
从正则表达式左侧开始,每出现一个左括号(
记做一个分组,分组编号从 1 开始。0 代表整个表达式。
Pattern p = Pattern.compile("(\\d{3,4})-(\\d{7,8})");
Matcher m = p.matcher("010-12345678");
if (m.matches()) {
System.out.println(m.groupCount());//2
System.out.println(m.group(0));//010-12345678
System.out.println(m.group(1));//010
System.out.println(m.group(2));//12345678
}
命名捕获组
每个以左括号开始的捕获组,都紧跟着 ?<name>
,而后才是正则表达式。
Pattern p = Pattern.compile("(?<num1>\\d{3,4})-(?<num2>\\d{7,8})");
Matcher m = p.matcher("010-12345678");
if (m.matches()) {
System.out.println(m.groupCount());//2
System.out.println(m.group(0));//010-12345678
System.out.println(m.group(1));//010
System.out.println(m.group(2));//12345678
System.out.println(m.group("num1"));//010
System.out.println(m.group("num2"));//12345678
}
非捕获组
在左括号后紧跟 ?:
,而后再加上正则表达式,构成非捕获组 (?:Expression)
。表示该括号只起包裹作用,不作为一组。
Pattern p = Pattern.compile("(\\d{3,4})-(?:\\d{7,8})");
Matcher m = p.matcher("010-12345678");
if (m.matches()) {
System.out.println(m.groupCount());//2
System.out.println(m.group(0));//010-12345678
System.out.println(m.group(1));//010
System.out.println(m.group(2));//报错:IndexOutOfBoundsException: No group 2
}
非贪婪匹配
(1)正则表达式默认使用贪婪匹配:任何一个规则,它总是尽可能多地向后匹配。
(2)例子:
给定一个字符串表示的数字,判断该数字末尾0
的个数。例如:
"123000"
:3个0
"10100"
:2个0
"1001"
:0个0
代码如下:
public class Main {
public static void main(String[] args) {
Pattern pattern = Pattern.compile("(\\d+)(0*)");
Matcher matcher = pattern.matcher("1230000");
if (matcher.matches()) {
System.out.println("group1=" + matcher.group(1)); // "1230000"
System.out.println("group2=" + matcher.group(2)); // ""
}
}
}
然而打印的第二个子串是空字符串""
,实际上我们期望的结果是"123"
和"000"
。
仔细观察上述实际匹配结果,实际上它是完全合理的,因为\d+
确实可以匹配后面任意个0
。
要让\d+
尽量少匹配,让0*
尽量多匹配,我们就必须让\d+
使用非贪婪匹配。在规则\d+
后面加个?
即可表示非贪婪匹配。我们改写正则表达式如下:
public class Main {
public static void main(String[] args) {
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"
}
}
}
分割字符串
"a b c".split("\\s"); // { "a", "b", "c" }
"a b c".split("\\s"); // { "a", "b", "", "c" }
"a, b ;; c".split("[\\,\\;\\s]+"); // { "a", "b", "c" }
搜索字符串
我想从字符串中找出3个字符:中间必须是o
,前后两个必须是字符[A-Za-z0-9_]
。
public class Main {
public static void main(String[] args) {
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);
System.out.println(m.group(0));//与sub相同
}
}
}
替换字符串
删除多余的空白符:
public class Main {
public static void main(String[] args) {
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."
}
}
反向引用
如果我们要把搜索到的指定字符串按规则替换,比如前后各加一个xxxx
,这个时候,使用replaceAll()
的时候,我们传入的第二个参数可以使用$1
、$2
来反向引用匹配到的子串。例如:
public class Main {
public static void main(String[] args) {
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); // "the quick brown fox jumps <b>over</b> the <b>lazy</b> dog."
}
}