六、正则表达式
05_Pattern、Matcher
Pattern、Matcher 06_Matcher示例
Matcher 常用方法找出所有匹配的子序列Matcher – 贪婪、勉强、独占的区别 07_贪婪、勉强、独占08_捕获组
捕获组 – 反向引用(Backreference) 09_边界匹配符
基本概念(终止符、输入、一行、单词边界)
05_Pattern、Matcher Pattern、MatcherString 的 matches 方法底层用到了 Pattern、Matcher 两个类;
// java.lang.String 源码:
public boolean matches(String regex) {
return Pattern.matches(regex, this);
}
// java.util.regex.Pattern 源码:
public static boolean matches(String regex, CharSequence input) {
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(input);
return m.matches();
}
06_Matcher示例
Matcher 常用方法
//如果整个input与regex匹配,就返回 true public boolean matches();
//如果从input中找到了与regex匹配的子序列,就返回 true //如果匹配成功,可以通过start、end、group方法获取更多信息 //每次的查找范围会先剔除此前已经查找过的范围 public boolean find();
//返回上一次匹配成功的开始索引 public int start();
//返回上一次匹配成功的结束索引 public int end();
//返回上一次匹配成功的input子序列 public String group();找出所有匹配的子序列
public static void findAll(String regex, String input) {
findAll(regex, input, 0);
}
public static void findAll(String regx, String input, int flags) {
if (regx == null || input == null) return;
Pattern p = Pattern.compile(regx, flags); // 编译正则, 看是否合法, flags代表模式
Matcher m = p.matcher(input); // 匹配, 返回一个匹配器
boolean found = false;
while (m.find()) {
found = true;
System.out.format(""%s", [%d, %d)%n", m.group(), m.start(), m.end());
}
if (!found) {
System.out.println("No match.");
}
}
Matcher - 示例:
findAll("\d{3}", "111_222_333_444_555");
String regex = "123"; findAll(regex, "123"); // "123", [0, 3) findAll(regex, "6_123_123_123_7");
String regex = "[abc]{3}";
findAll(regex, "abccabaaaccbbbc");
String regex = "\d{2}";
findAll(regex, "0_12_345_67_8");
String input = "";
findAll("a?", input);
// "", [0, 0)
String input = "";
findAll("a?", input);
// "", [0, 0)
findAll("a*", input);
// "", [0, 0)
findAll("a+", input);
// No match.
String input = "a";
findAll("a?", input);
// "a", [0, 1)
// "", [1, 1)
findAll("a*", input);
// "a", [0, 1)
// "", [1, 1)
findAll("a+", input);
// "a", [0, 1)
String input = "abbaaa";
findAll("a?", input);
findAll("a*", input);
findAll("a+", input);
// "a", [0, 1)
// "aaa", [3, 6)
Matcher – 贪婪、勉强、独占的区别
这里再次放出这张表
String input = "afooaaaaaafooa";
findAll(".*foo", input); // 贪婪
// "afooaaaaaafoo", [0, 13)
findAll(".*?foo", input); // 勉强
// "afoo", [0, 4)
// "aaaaaafoo", [4, 13)
findAll(".*+foo", input); // 独占
// No match.
07_贪婪、勉强、独占
贪婪
先吞掉整个input进行匹配
若匹配失败,则吐出最后一个字符 然后再次尝试匹配,重复此过程,直到匹配成功
勉强
先吞掉input的第一个字符进行匹配
若匹配失败,则再吞掉下一个字符 然后再次尝试匹配,重复此过程,直到匹配成功
独占
吞掉整个input进行唯一的次匹配
String input = "afooaaaaaafooa";
findAll(".*foo", input); // 贪婪
// "afooaaaaaafoo", [0, 13)
findAll(".*?foo", input); // 勉强
// "afoo", [0, 4)
// "aaaaaafoo", [4, 13)
findAll(".*+foo", input); // 独占
// No match.
08_捕获组
简单的说,一对小括号里的内容就是一个捕获组;
String regex1 = "dog{3}";
"doggg".matches(regex1); // true
String regex2 = "[dog]{3}";
"ddd".matches(regex2); // true
"ooo".matches(regex2); // true
"ggg".matches(regex2); // true
"dog".matches(regex2); // true
"gog".matches(regex2); // true
"gdo".matches(regex2); // true
// ... 共 3 * 3 * 3 = 27 种可能
// (dog)就是一个捕获组
String regex3 = "(dog){3}";
"dogdogdog".matches(regex3); // true
捕获组 – 反向引用(Backreference)
反向引用: 可以使用反斜杠+ 组编号(从 1 开始)来引用组的内容
// (\d\d)是一个捕获组, \1表示引用第一个捕获组(内容要相同) String regex = "(\d\d)\1"; "1212".matches(regex); // true "1234".matches(regex); // false
// 总共有2个组
// 编号1: ([a-z]{2})
// 编号2: ([A-Z]{2})
// \2\1 表示先引用第2组再引用第1组
String regex = "([a-z]{2})([A-Z]{2})\2\1";
"mjPKPKmj".matches(regex); // true
"mjPKmjPK".matches(regex); // false
// 总共有4个组
// 编号1: ((I)( Love( You)))
// 编号2: (I)
// 编号3: ( Love( You))
// 编号4: ( You)
// \3{2} 表示引用2次第3组, 即后面跟 "Love You Love You"
String regex = "((I)( Love( You)))\3{2}";
"I Love You Love You Love You".matches(regex); // true
String input = "aaabbbb";
// 下面的正则等价于: "([a-z])\1{3}"
String regex = "([a-z])\1\1\1";
findAll(regex, input);
09_边界匹配符
基本概念(终止符、输入、一行、单词边界)
终止符(Final Terminator、Line Terminator)
r(回车符)、n(换行符)、rn(回车换行符)
输入:整个字符串
一行:以终止符(或整个输入的结尾)结束的字符串片段
如果输入是 dogndogrdog那么 3 个 dog 都是一行
(匹配模式要设置为多行模式,终止符才会生效,否则还是看作单行)
单词边界:
// 哪些东西是单词边界?
// 除开英文字母大小写、阿拉伯数字、下划线、其他国家的正常文字以外的字符
String input = "dog_dog6dog+dog-dog哈";
findAll("\bdog\b", input);
// "dog", [12, 15)
b 代表单词边界:
// \b是单词边界, 要求dog左边和右边都是单词边界 String regex = "\bdog\b"; // " " 和 "." 是单词边界 findAll(regex, "This is a dog."); // "dog", [10, 13) findAll(regex, "This is a doggie."); // No match. // 开头视作单词边界 findAll(regex, "dog is cute"); // "dog", [0, 3) // ","是单词边界 findAll(regex, "I love cat,dog,pig."); // "dog", [11, 14)
B 代表非单词边界:
// dog左边是单词边界, dog右边不是单词边界 String regex = "\bdog\B"; findAll(regex, "This is a dog."); // No match. findAll(regex, "This is a doggie."); // "dog", [10, 13) findAll(regex, "dog is cute"); // No match. findAll(regex, "I love cat,dog,pig."); // No match.
^ 代表一行的开头,$ 代表一行的结尾:
// ^是一行的开头, $是一行的结尾
// 要求dog, 且d是行开头, g是行结尾
String regex = "^dog$";
findAll(regex, "dog");
// "dog", [0, 3)
findAll(regex, " dog");
// No match.
// -------------------------------------
findAll("\s*dog$", " dog");
// " dog", [0, 7)
findAll("^dog\w*", "dogblahblah");
// "dogblahblah", [0, 11)
A 代表 输入的开头、z 代表输入的结尾、Z 代表输入的结尾(结尾可以有终结符):
// "A" 代表输入的开头 // "z" 代表输入的结尾 // "Z" 代表输入的结尾(结尾可以有终结符) String regex1 = "\Adog\z"; String regex2 = "\Adog\Z"; findAll(regex1, "dog"); // "dog", [0, 3) findAll(regex2, "dog"); findAll(regex1, "dogn"); // No match. findAll(regex2, "dogn"); // "dog", [0, 3) findAll(regex1, "dogndogrdog"); // No match. findAll(regex2, "dogndogrdog"); // No match. findAll(regex1, "dogndogrdog", Pattern.MULTILINE); // No match. findAll(regex2, "dogndogrdog", Pattern.MULTILINE); // No match.
G 代表上一次匹配的结尾(很少用到)
// 开头看做一次匹配的结尾 String regex = "\Gdog"; findAll(regex, "dog"); // "dog", [0, 3) findAll(regex, "dog dog"); // "dog", [0, 3) findAll(regex, "dogdog"); // "dog", [0, 3) // "dog", [3, 6)



