正则表达式简介
Java中有关正则表达式的包的位置
简单示例
public static void main(String[] args) {
// 正则表达式
String numberReg = "^\\d+$";
// 要匹配的正确和错误的字符串
String rightNumber = "15927601529";
String wrongNumber = "159dd2760";
System.out.println(Pattern.matches(numberReg, rightNumber)); // true
System.out.println(Pattern.matches(numberReg, wrongNumber)); // false
}
正则表达式基础
正则表达式不仅可以匹配字符,还可以寻找位置。对于没有给定要匹配的字符,则默认是匹配符合条件的位置
匹配字符参考示例
// 驼峰转下划线
public static void underLineToHump() {
String s = "hump_to_under_line";
// 匹配大写字母前的位置,这里并没有给定要匹配的字符,所以是匹配位置
String regExp = "_(\\w)";
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(s);
StringBuilder sb = new StringBuilder();
while (matcher.find()) {
// appendReplacement方法:sb是一个StringBuffer,replaceContext待替换的字符串,这个方法会把匹配到的内容替换为replaceContext,
// 并且把从上次替换的位置到这次替换位置之间的字符串也拿到,然后加上这次替换后的结果一起追加到StringBuffer里(假如这次替换是第一次替换,那就是只追加替换后的字符串)。
matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
}
// appendTail方法:sb是一个StringBuffer,这个方法是把最后一次匹配到内容之后的字符串追加到StringBuffer中。
matcher.appendTail(sb);
System.out.println("下划线转驼峰:" + sb.toString());
}
匹配位置参考示例
// 驼峰转下划线
public static void humpToUnderLine() {
String s = "humpToUnderLine";
// 匹配大写字母前的位置,这里并没有给定要匹配的字符,所以是匹配位置
String regExp = "(?=[A-Z])";
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(s);
String underLine = matcher.replaceAll("_").toLowerCase();
System.out.println(underLine);
}
常规字符的匹配
字母、数字、汉字、没有特殊定义的标点符号,都属于“常规字符”的定义。
参考代码
public static void normalStrReg(){
// 定义正则表达式
String regExp = "abc";
// 待匹配的字符串
String s = "acdb,abc,aaa, abc";
// 得到正则表达式对象
Pattern pattern = Pattern.compile(regExp);
// 将匹配结果存储到Matcher对象中
Matcher matcher = pattern.matcher(s);
// 可以输出多个结果,find方法内部维护的有指针,每调用一次是移动的
while (matcher.find()) {
System.out.println(matcher.group());
}
}
简单转义字符的匹配
简单转义字符,制表符\t,回车符和换行符\r,\n,反斜杠\
参考代码
// 简单转义字符
public static void simpleEscapeString() {
// 定义正则表达式,分别匹配制表符和 “\”
String regExp1 = "\\t";
// 字符串中一个\要有两个\\来表示,所以这里需要两个转义符号
String regExp2 = "\\\\";
// 待匹配的字符串
String s = "a\tbc,d\\stat";
System.out.println(s);
// 得到正则表达式对象
Pattern pattern1 = Pattern.compile(regExp1);
Pattern pattern2 = Pattern.compile(regExp2);
// 进行匹配
System.out.println(pattern1.matcher(s).find());
System.out.println(pattern2.matcher(s).find());
}
某一类特定规律的字符
正向匹配
比如下图中的特殊规律字符
参考代码
// 匹配特殊规律的字符
public static void specialChar() {
// 匹配数字,“+”表示一个或多个
String regExp1 = "\\d+";
String s1 = "12zhang_342 wut 1";
// 获得对象
Pattern pattern1 = Pattern.compile(regExp1);
// 获得结果
Matcher matcher1 = pattern1.matcher(s1);
System.out.println("多个数字匹配:");
while (matcher1.find()) {
System.out.println(matcher1.group());
}
// 匹配多个字符
String regExp2 = "\\w+";
String s2 = "12zhang_ 342&张 wut 1";
Pattern pattern2 = Pattern.compile(regExp2);
Matcher matcher2 = pattern2.matcher(s2);
System.out.println("多个字符匹配:");
while (matcher2.find()) {
System.out.println(matcher2.group());
}
// 匹配多个空格、制表符、换页符等空白字符
String regExp3 = "\\s+";
String s3 = "12zhang_ 342&张 wut 1";
Pattern pattern3 = Pattern.compile(regExp3);
Matcher matcher3 = pattern3.matcher(s3);
System.out.println("多个空白字符匹配:");
while (matcher3.find()) {
System.out.println(matcher3.group());
}
// 匹配多个非换行符的字符
String regExp4 = "helloWorld(.*)helloWorld";
String s4 = "helloWorld张_12helloWorld";
Pattern pattern4 = Pattern.compile(regExp4);
Matcher matcher4 = pattern4.matcher(s4);
System.out.println("使用.*多个字符匹配:");
while (matcher4.find()) {
// 注意这里的group(1)而不是group(),因为是(.*)形式的
System.out.println(matcher4.group(1));
}
}
反向匹配
和正向匹配字符取反
参考代码
// 特殊规律字符反向匹配
public static void specialCharReverse() {
// 匹配非数字,“+”表示一个或多个
String regExp1 = "\\D+";
String s1 = "12zhang_342 wut 1";
// 获得对象
Pattern pattern1 = Pattern.compile(regExp1);
// 获得结果
Matcher matcher1 = pattern1.matcher(s1);
System.out.println("匹配非数字:");
while (matcher1.find()) {
System.out.println(matcher1.group());
}
// 匹配多个非 \w 匹配的字符
String regExp2 = "\\W+";
String s2 = "12zhang_ 342&张 wut 1";
Pattern pattern2 = Pattern.compile(regExp2);
Matcher matcher2 = pattern2.matcher(s2);
System.out.println("多个非\\w字符匹配:");
while (matcher2.find()) {
System.out.println(matcher2.group());
}
// 匹配多个非空白字符
String regExp3 = "\\S+";
String s3 = "12zhang_ 342&张 wut 1";
Pattern pattern3 = Pattern.compile(regExp3);
Matcher matcher3 = pattern3.matcher(s3);
System.out.println("多个非空白字符匹配:");
while (matcher3.find()) {
System.out.println(matcher3.group());
}
// 匹配多个非边界字符,\B和\b匹配的是光标的位置,而非哪一个字符
String regExp4 = "w\\Bww";
String s4 = "helloWorld 张_12 hello World! www";
Pattern pattern4 = Pattern.compile(regExp4);
Matcher matcher4 = pattern4.matcher(s4);
System.out.println("多个非边界字符匹配:");
while (matcher4.find()) {
System.out.println(matcher4.group());
}
}
自定义能够匹配某一列字符的表达式
如下图自定义的表达式
参考代码
// 自定义匹配某一类字符的表达式
public static void customExp() {
// 自定义表达式匹配,中括号表示匹配里面的一个字符,+表示一个或多个
String regExp = "[@#&]+";
String s = "@##&12zhang&_342 #wut 1";
// 获得对象
Pattern pattern = Pattern.compile(regExp);
// 获得结果
Matcher matcher = pattern.matcher(s);
System.out.println("自定义匹配@#&:");
while (matcher.find()) {
System.out.println(matcher.group());
}
}
用来匹配特殊位置的字符
这些字符匹配的是位置,而不是哪一个字符
参考代码
// 匹配特殊位置的字符,匹配位置而不是字符
public static void positinoRegExp() {
// 这里匹配的是以数字开头,数字结尾,中间有一个或多个字符
String regExp = "^\\d.+\\d$";
String s = "1231zhang_@#123";
// String s = "1231zhang_@#123a"; // 未匹配成功
// 获得对象
Pattern pattern = Pattern.compile(regExp);
// 获得结果
Matcher matcher = pattern.matcher(s);
System.out.println("匹配特殊位置:");
while (matcher.find()) {
System.out.println(matcher.group());
}
// \b的作用,包括单词的左右边界
String line = "hello world \t张!";
System.out.println("原始字符串line:" + line);
line = line.replaceAll("\\b", "#");
字符串line:" + line);
line = line.replaceAll("\\b", "#");
System.out.println("修改之后的字符串line:" + line); // #hello# #world# #张#!
}
修改匹配次数的特殊字符
参考代码
// 修改匹配次数
public static void matchCountRegExp() {
// String regExp = "a{2}"; // aa
// String regExp = "b{2,4}"; // bbbb
String regExp = "c{5,}"; // cccccc
String s = "aaabbbbbcccccc";
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(s);
while (matcher.find()) {
System.out.println(matcher.group());
}
}
匹配特殊字符本身
参考代码
// 修改匹配次数
public static void matchCountRegExp() {
// String regExp = "a{2}"; // aa
// String regExp = "b{2,4}"; // bbbb
String regExp = "c{5,}"; // cccccc
String s = "aaabbbbbcccccc";
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(s);
System.out.println("匹配特殊字符本身:");
while (matcher.find()) {
System.out.println(matcher.group());
}
}
正则表达式原理
如下图所示
正则表达式进阶
正则表达式子表达式之间的关系
在获取括号匹配到的内容时,如果使用group()不带参数默认是输出整个字符串,如果传入参数,使用group(1)则表示第一个括号匹配到的内容
参考代码
// 正则表达式子表达式的关系
public static void subRegExp(){
// 小括号的含义
String regExp = "https://www.(.*)(\\.com)";
String s = "https://www.baidu.com";
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(s);
System.out.println("()的含义:");
while (matcher.find()) {
System.out.println(matcher.group()); // https://www.baidu.com
// 输出对应括号的匹配的内容
System.out.println(matcher.group(1)); // baidu
System.out.println(matcher.group(2)); // .com
}
// |的效果,或的含义
String regExp2 = "zhang|wang";
String s2 = "zhang li liang wang zhang";
Pattern pattern2 = Pattern.compile(regExp2);
Matcher matcher2 = pattern2.matcher(s2);
System.out.println("|的含义:");
while (matcher2.find()) {
System.out.println(matcher2.group());
}
}
匹配次数的贪婪与非贪婪
上图中缺少了\,应该是(\d)(\w+)和(\d)(\w+)(\d)
贪婪就是尽可能多的去匹配,非贪婪就是尽可能少的去匹配。对于可以多次匹配的字符,默认是贪婪的,可以在后面添加 ”?“ 实现尽可能少的去匹配。但对于上述的 (d)(w+)(d) 形式,(w+) 则是贪婪的,因为只有匹配了(w+)的内容,才可继续匹配后面(d)的内容。
参考代码
// 匹配次数的贪婪与非贪婪
public static void greedOrNoGreedRegExp(){
// 添加?实现非贪婪
String regExp = "c{3,}?";
String s = "aabcccc";
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(s);
System.out.println("非贪婪匹配:");
while (matcher.find()) {
System.out.println(matcher.group());
}
// 这里使用了?,但效果依然是贪婪的,因为只有匹配了(w+)对应的全部内容,才能继续匹配后面(d)的内容
String regExp2 = "(\\d)(\\w+?)(\\d)";
String s2 = "zhang li liang wang 1zhang2";
Pattern pattern2 = Pattern.compile(regExp2);
Matcher matcher2 = pattern2.matcher(s2);
System.out.println("关于非贪婪的另一个例子:");
while (matcher2.find()) {
System.out.println(matcher2.group());
}
}
反向引用
反向引用就是引用 ”()” 已经匹配的到结果作为正则表达式的一部分
参考代码
// 反向引用,引用”()“已经匹配到的字符串作为正则表达式后续的一部分呢
public static void backReferenceRegExp(){
// 反向引用,匹配出标签以及标签啊内容
String regExp = "<(.+)>.*</(\\1)>";
String s = "<div> zhang </div> <span> <button> button </button> </span>";
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(s);
System.out.println("反向引用:");
while (matcher.find()) {
System.out.println(matcher.group());
}
}
正向预搜索匹配与正向预搜索不匹配
正向预搜索匹配,就是搜索到一个待匹配项时,判断后续字符是否符合给定的要求,符合则成功匹配
正向预搜索不匹配,就是搜索到一个待匹配项时,判断后续字符是否符合给定的要求,不符合则成功匹配
参考代码
// 正向预搜索匹配与正向预搜索不匹配
public static void matchOrNoteMatchRegExp() {
// 正向与搜索,就是搜索到一个待匹配项时,判断后续字符是否符合给定的要求,符合则成功匹配。下面的例子会匹配到一个good前面的java
String regExp = "java\\s(?=good)";
String s = "java bad,java good,java and python";
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(s);
System.out.println("正向预搜索匹配:");
while (matcher.find()) {
System.out.println(matcher.group()); // java
System.out.println("匹配串后面剩余的所有字符:" + s.substring(matcher.end() - 1));
}
// 正向与搜索不匹配
String regExp1 = "java\\s(?!good)";
String s1 = "java bad,java good,java and python";
Pattern pattern1 = Pattern.compile(regExp1);
Matcher matcher1 = pattern1.matcher(s1);
System.out.println("正向预搜索不匹配:");
while (matcher1.find()) {
System.out.println(matcher1.group()); // java
System.out.println("匹配串后面剩余的所有字符:" + s1.substring(matcher1.end() - 1));
}
}
反向预搜索匹配与反向预搜索不匹配
反向预搜索匹配,就是搜索到一个待匹配项时,判断前面的字符是否符合给定的要求,符合则成功匹配
反向预搜索不匹配,就是搜索到一个待匹配项时,判断前面的字符是否符合给定的要求,不符合则成功匹配
参考代码
// 反向预搜索匹配与反向预搜索不匹配
public static void matchOrNoteMatchReverseRegExp() {
// 反向与搜索,就是搜索到一个待匹配项时,判断前面的字符是否符合给定的要求,符合则成功匹配。下面的例子会匹配到一个good前面的java
// 小于等于号 ”<=“ 表示左边方向
String regExp = "(?<=(hello\\s))java";
String s = "123 1hello java java bad java good java and python";
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(s);
System.out.println("反向预搜索匹配:");
while (matcher.find()) {
System.out.println(matcher.group()); // 输出hello后的java
System.out.println("匹配串后面剩余的所有字符:" + s.substring(matcher.end()));
}
// 反向与搜索不匹配
String regExp1 = "(?<!(hello\\s))java";
String s1 = "123 1hello java java bad java good java and python";
Pattern pattern1 = Pattern.compile(regExp1);
Matcher matcher1 = pattern1.matcher(s1);
System.out.println("反向预搜索不匹配:");
while (matcher1.find()) {
System.out.println(matcher1.group()); // java
System.out.println("匹配串后面剩余的所有字符:" + s1.substring(matcher1.end()));
}
}
各语言通用规则之汉字匹配
参考代码
// 各语言通用规则之汉字匹配使用16进制代替
public static void unicodeRegExp() {
// 汉字匹配,使用16进制编码代替,武汉理工大学的Unicode编码为\u6b66\u6c49\u7406\u5de5\u5927\u5b66\u000d\u000a\u000d\u000a
// \u6b67是岐
String regExp = "[\\u6b66-\\u6b67]";
String s = "hello 武汉理工大学 hello";
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(s);
System.out.println("汉字匹配:");
while (matcher.find()) {
System.out.println(matcher.group());
}
}
各语言需要转义的字符列表
不对子表达式进行捕获
参考代码
// 不捕获子表达式
public static void notMatchSubRegExp() {
String s = "take me to your heart 123take15 me 武汉理工大学 hello";
// (?:\d+) 这个表示在使用group(index)捕获匹配内容时,不对该子表达式捕获,不计入表达式的数量中
String regExp = "(?:\\d+)(.*?)(\\d+)";
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(s);
System.out.println("不捕获子表达式:");
while (matcher.find()) {
System.out.println(matcher.group(1)); // 输出:take
}
}
表达式常用属性设置
参考代码
// 常用属性设置
public static void usualConfigurationRegExp() {
String s = "hello world Hello Man HELLO python \n choosepython";
String regExp = "hello";
// 设置大小写不敏感
Pattern pattern = Pattern.compile(regExp,Pattern.CASE_INSENSITIVE);
// 默认大小写敏感
// Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(s);
System.out.println("大小写不敏感:");
while (matcher.find()) {
System.out.println(matcher.group());
}
String s1 = "hello world Hello Man HELLO python\n choosepython";
String regExp1 = ".*python$";
// 设置多行匹配
Pattern pattern1 = Pattern.compile(regExp1,Pattern.MULTILINE);
// 默认单行匹配
// Pattern pattern1 = Pattern.compile(regExp1);
Matcher matcher1 = pattern1.matcher(s1);
System.out.println("多行匹配:");
while (matcher1.find()) {
System.out.println(matcher1.group());
}
}