正则表达式笔记

正则表达式

1、匹配符号

正则的 \ 在 java z中要写两个 \。下面均为java 中用法。

  • 例子:匹配电话号码:

    String re = "0\\d{2,3}-[1-9]\\d{6,7}";
    s.matches(re);
    

2、简单匹配规则

符号 说明 用法
\\u548c 匹配Unicode码 中文字符
\\d 匹配单个数字 String re2 = "a\\&c"; // 对应的正则是a\&c
System.out.println("a&c".matches(re2));
. 匹配任意一个字符 a.c 可以匹配abc 、 a&c 等
\\w 匹配数字字母下划线 ac\w 可以匹配 ac1 、acb、ac_等
\\s 匹配一个空格或tab (\t) a\sc 可以匹配 a c 和 a(tab)c
\\D \\W 匹配非数字和非字符
[num1-num2] 匹配这之间的任意一个字符
\\S 匹配非空格
\d* 匹配任意多个数字
\d+ 匹配至少一个数字
\d? 匹配0个或1个数字
\d 精确匹配n个数字
\d 匹配m~n个字符

3、复杂匹配规则

一些例子:
1、匹配开头和结尾:
	^表示开头,$表示结尾;比如:
	^A\d{3}$ 可以匹配 A123 
2、匹配指定范围:
	使用[]限定范围。匹配里面的字符或数字。比如:
	[0-8] 可以匹配 0-8 (闭区间)任意一个字符
	[0-9a-fA-F] 可以匹配十六进制数字
3、或匹配规则:
	ad|cd 用来匹配 ab 或者 cd  
	String re = "java|php";
4、使用括号:
	匹配多个或时 可以将公共部分抽取出来,比如:
	String re = "learn\\s([jJ]ava|[pP]hp|[pP]ython)" 匹配:learn java

4、分组匹配

  • 使用()来分组。主要目的是获取字符串时便捷的获取个部分内容。

    比如:(\\d{3,4})\\-(\\d{7,8}) 
    使用Pattern 对象的 matcher方法获取一个 matcher 对象 m。
    使用 m.group(index)就能获取 各个组的内容。
    当 index 为零时,获取整个字符串。
    
  • 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("匹配失败!");
            }
    
  • 使用 String 的matches 方法和 直接创建 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(); // 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个子串
                System.out.println(area);
                System.out.println(tel);
            }
    

    习题:获取时分秒信息:

    String str = "23:12:59";
    Pattern p = Pattern.compile("([0-1]\\d|2[0-3]):([0-5]\\d):([0-5]\\d)");
    Matcher m = p.matcher(str);
    //判断是否匹配成功
    if(m.matches()){
    	String hours = m.group(1);
    	......
    }eles{
    	......
    }
    

5、非贪婪匹配

  • 正则表达式默认使用贪婪匹配。即:对任意一个规则,总是尽可能多的向后匹配。

  • 实例描述:

    给定一个字符串,统计后面 0 的个数。若使用(\\d+)(0*) 分组匹配,由于贪婪匹配的存在,\\d+ 会把后面的0 也匹配到前面去。导致 0* 分组个数为0
    
  • 解决方法:使用非贪婪匹配,在匹配规则后面加上 ?即可。\\d+?

     	    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"
            }
    
    • 特例

      正则表达式(\d??)(9*),注意\d?表示匹配0个或1个数字,后面第二个?表示非贪婪匹配,因此,给定字符串"9999",匹配到的两个子串分别是""和"9999",因为对于\d?来说,可以匹配1个9,也可以匹配0个9,但是因为后面的?表示非贪婪匹配,它就会尽可能少的匹配,结果是匹配了0个9。
      

6、搜索和替换

  • String.split()方法传递的正是正则表达式。正则能实现更加灵活的功能。

    ****\\s 参数替换一个或多个空格,但是这里替换之后变成了空字符串"" 。而不是直接没了。

"a b c".split("\\s"); // { "a", "b", "c" }
"a b  c".split("\\s"); // { "a", "b", "", "c" }
"a, b ;; c".split("[\\,\\;\\s]+"); // { "a", "b", "c" }
  • 搜索字符串:

    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);
            }
    
  • 替换字符串

    String.replaceAll()方法第一的参数是正则表达式,第二个参数是待替换的字符串。
    String s = "The     quick\t\t brown   fox  jumps   over the  lazy dog.";
            String r = s.replaceAll("\\s+", " ");
            
    结果:"The quick brown fox jumps over the lazy dog."
    
  • 反向引用:使用replaceAll()方法的第二个参数指定对匹配到的字符串的操作

    如果我们要把搜索到的指定字符串按规则替换,比如前后各加一个<b>xxxx</b>,这个时候,使用replaceAll()的时候,我们传入的第二个参数可以使用$1、$2来反向引用匹配到的子串。
    
     String s = "the quick brown fox jumps over the lazy dog.";
            String r = s.replaceAll("\\s([a-z]{4})\\s", " <b>$1</b> ");
            
     result: the quick brown fox jumps <b>over</b> the <b>lazy</b> dog. 
    
  • ################ 未理解 ####################

  • 使用appendReplacement 和 appendTail 进行模板替换

  • Matcher m = pattern.matcher(template);
    StringBuilder sb = new StringBuilder();
    while (m.find()) {
        m.appendReplacement(sb, data.get(m.group(1)).toString());
    }
    m.appendTail(sb);
    return sb.toString();
    
  • 用法实例:

    public class TheReplacements {
        public static void main(String[] args) throws Exception {
            // 生成 Pattern 对象并且编译一个简单的正则表达式"cat"
            Pattern p = Pattern.compile("cat");
            // 用 Pattern 类的 matcher() 方法生成一个 Matcher 对象
            Matcher m = p.matcher("fatcatfatcatfat");
            StringBuffer sb = new StringBuffer();
            while(m.find()){
                //此时sb为fatdogfatdog,cat被替换为dog,并且将最后匹配到之前的子串都添加到sb对象中
                m.appendReplacement(sb,"dog");
            }
            //此时sb为fatdogfatdogfat,将最后匹配到后面的子串添加到sb对象中
            m.appendTail(sb);
            //输出内容为fatdogfatdogfat
            System.out.println("sb:"+sb);
        }
    }
    
    a b a b a a b
    a b a b c
posted @ 2022-05-08 14:40  心是冰冰的  阅读(114)  评论(0)    收藏  举报