Java基础——正则表达式

71 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情

一、概念

正则表达式可以用字符串来描述规则,并用来匹配字符串。例如,判断手机号,我们用正则表达式\d{11}

 boolean isValidMobileNumber(String s) {
     return s.matches("\d{11}");
 }

Java标准库的java.util.regex包内置了正则表达式引擎,注意Java字符串用\表示``。

二、匹配规则

匹配任意字符:.

匹配数字:\d

匹配非数字:\D

匹配常用字符(字母、数字或下划线):\w

匹配非常用字符:\W

匹配空格字符(空格、Tab):\s

匹配非空格字符:\S

重复匹配

修饰符*可以匹配任意个字符,包括0个字符

修饰符+可以匹配至少一个字符

修饰符?可以匹配0个或一个字符

修饰符{n}精确指定n个字符

修饰符{n,m}指定匹配n~m个字符

修饰符{n,}可以匹配至少n个字符

三、复杂匹配规则

匹配开头和结尾:^表示开头,$表示结尾

匹配指定范围:[...]可以匹配范围内的字符,[1-9],[0-9a-fA-F]

不包含指定范围的字符:[^...]

或规则匹配:用|连接的两个正则规则

使用括号:可以把公共部分提出来,然后用(...)把子规则括起来表示成learn\s(java|php|go)

四、分组匹配

(...)先把要提取的规则分组,没办法用String.matches()这样简单的判断方法了,必须引入java.util.regex包,用Pattern对象匹配,匹配后获得一个Matcher对象,如果匹配成功,就可以直接从Matcher.group(index)返回子串

要特别注意,Matcher.group(index)方法的参数用1表示第一个子串,2表示第二个子串。如果我们传入0会得到什么呢?答案是010-12345678,即整个正则匹配到的字符串。

使用Matcher时,必须首先调用matches()判断是否匹配成功,匹配成功后,才能调用group()提取子串。

五、非贪婪匹配

正则表达式默认使用贪婪匹配:任何一个规则,它总是尽可能多地向后匹配。

给定一个匹配规则,加上?后就变成了非贪婪匹配。

六、搜索和替换

分割字符串

使用正则表达式分割字符串可以实现更加灵活的功能。String.split()方法传入的正是正则表达式。我们来看下面的代码:

 "a b c".split("\s"); // { "a", "b", "c" }
 "a b  c".split("\s"); // { "a", "b", "", "c" }
 "a, b ;; c".split("[\,\;\s]+"); // { "a", "b", "c" }

搜索字符串

获取到Matcher对象后,不需要调用matches()方法(因为匹配整个串肯定返回false),而是反复调用find()方法,在整个串中搜索能匹配上\wo\w规则的子串,并打印出来。这种方式比String.indexOf()要灵活得多,因为我们搜索的规则是3个字符:中间必须是o,前后两个必须是字符[A-Za-z0-9_]

替换字符串

使用正则表达式替换字符串可以直接调用String.replaceAll(),它的第一个参数是正则表达式,第二个参数是待替换的字符串。

反向引用

如果我们要把搜索到的指定字符串按规则替换,比如前后各加一个<b>xxxx</b>,这个时候,使用replaceAll()的时候,我们传入的第二个参数可以使用$1$2来反向引用匹配到的子串

 package com.study.regex;
 ​
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 ​
 public class RegexDemo {
     public static void main(String[] args) {
         demo1();
         System.out.println("==================================");
 ​
         demo2();
         System.out.println("==================================");
 ​
         demo3();
         System.out.println("==================================");
 ​
         demo4();
         System.out.println("==================================");
 ​
         demo5();
     }
 ​
     private static void demo1() {
         String regex = "20\d\d";
         System.out.println("2019".matches(regex));
         System.out.println("2100".matches(regex));
         System.out.println("=====================");
 ​
         String re1 = "a\&c"; // 对应的正则是a&c
         System.out.println("a&c".matches(re1));
         System.out.println("a-c".matches(re1));
         System.out.println("a&&c".matches(re1));
         System.out.println("=====================");
 ​
         String re2 = "a\u548cc";  // 中文用\u####的十六进制表示
         System.out.println("a和c".matches(re2));
         System.out.println("=====================");
 ​
         String re3 = "java|php";
         System.out.println("java".matches(re3));
         System.out.println("php".matches(re3));
         System.out.println("go".matches(re3));
         System.out.println("=====================");
 ​
         String re4 = "learn\s(java|php|go)";
         System.out.println("learn java".matches(re4));
         System.out.println("learn Java".matches(re4));
         System.out.println("learn php".matches(re4));
         System.out.println("learn Go".matches(re4));
     }
 ​
     private static void demo2() {
         Pattern p = Pattern.compile("(\d{3,4})-(\d{7,8})");
         Matcher m = p.matcher("010-12345678");
         if (m.matches()) {
             String g0 = m.group(0); // 0表示匹配的整个字符串
             String g1 = m.group(1); // 1表示匹配的第1个子串
             String g2 = m.group(2); // 2表示匹配的第2个子串
             System.out.println(g0);
             System.out.println(g1);
             System.out.println(g2);
         } else {
             System.out.println("匹配失败!");
         }
     }
 ​
     // 非贪婪匹配
     private static void demo3() {
         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"
         }
     }
 ​
     private static void demo4() {
         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); // row fox dog
         }
     }
 ​
     private static void demo5() {
         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."
 ​
         r = r.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.
     }
 }
 ​