Java学习之正则表达式篇


快速入门

import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * @Author: mei_ming
 * @DateTime: 2022/6/4 16:25
 * @Description: 体验正则表达式
 */
public class Regexp_ {

    @Test
    public void test1(){
//        String content="2000年5月,JDK1.3、JDK1.4和J2SE1.3相继发布," +
//                "几周后其获得了Apple公司Mac OS X的工业标准的支持。2001年9月24日," +
//                "J2EE1.3发布。2002年2月26日,J2SE1.4发布。自此Java的计算能力有了大幅提升" +
//                ",与J2SE1.3相比,其多了近62%的类和接口。在这些新特性当中,还提供了广泛的XML支持、" +
//                "安全套接字(Socket)支持(通过SSL与TLS协议)、全新的I/OAPI、正则表达式、日志与断言。" +
//                "2004年9月30日,J2SE1.5发布,成为Java语言发展史上的又一里程碑。为了表示该版本的重要性," +
//                "J2SE 1.5更名为Java SE 5.0(内部版本号1.5.0),代号为“Tiger”,Tiger包含了从1996年发布" +
//                "1.0版本以来的最重大的更新,其中包括泛型支持、基本类型的自动装箱、改进的循环、枚举类型、格式化I/O及可变参数。";

        //百度热搜  代码简化后
        String content =
                "<div class=\"FYB_RD\"><div class=\"cr-title c-gap-bottom-xsmall\" " +
                        "data-click=\"true\" title=\"百度热搜\"><a class=\"c-color-t opr-toplist1-title_1LgpS\" " +
                        "<a target=\"_blank\" title=\"考生:3年的数学难题都在卷子里\" href=\"https://top.baidu.co" +
                        "<a target=\"_blank\" title=\"湖北考生请枪手代答?当地辟谣\" href=\"/s?wd=%E6%B9%96%E5%8C%97%E8%80%83" +
                        "<a target=\"_blank\" title=\"成都考生提前一小时答完数学题\" href=\"/s?wd=%E6%88%90%E9%83%BD%E8%8";

        //提取文章中的所有的英文单词

        //(1) 传统方法,使用遍历方式,代码量大,效率不高
        //(2) 正则表达式

        //1. 创建Pattern对象,
        //提取文章中的所有的英文单词
        //Pattern pattern = Pattern.compile("[a-zA-Z]+");
        //提取文章中的所有的数字
        //Pattern pattern = Pattern.compile("[0-9]+");
        //提取文章中的所有的英文单词和数字
        //Pattern pattern = Pattern.compile("([a-zA-Z]+)|([0-9]+)");
        //提取百度热搜的标题
        Pattern pattern = Pattern.compile("<a target=\"_blank\" title=\"(\\S*)\"");
        //2. 创建匹配器对象
        // 理解 matcher 匹配器按照pattern模式对象,到content文本中去匹配
        // 找到则返回true, 否则返回false
        Matcher matcher = pattern.matcher(content);
        //3. 可以开始循环匹配
        while(matcher.find()){
            //匹配内容,文本,放到 matcher.group(0)
            System.out.println("找到:" + matcher.group(1));
        }
    }
}

学习正则表达式可以快速验证邮箱格式、手机格式等
正则表达式是对字符串执行模式匹配的技术


正则表达式基本语法

从功能上看,共有六大类元字符
转义号 \
\ 符号说明:在我们使用正则表达式去检索某些特殊字符的时候,需要用到转义符号,否则检索不到结果。如下所示:

import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Author: mei_ming
 * @DateTime: 2022/6/8 22:29
 * @Description: 演示转义符号的使用
 */
public class Regexp_02 {

    @Test
    public void test() {
        String content = "abc()def.123(";
        //匹配 ( => \\(
        //匹配 . => \\.
        Pattern pattern = Pattern.compile("\\.");
        //2. 创建匹配器对象
        // 理解 matcher 匹配器按照pattern模式对象,到content文本中去匹配
        // 找到则返回true, 否则返回false
        Matcher matcher = pattern.matcher(content);
        //3. 可以开始循环匹配
        while (matcher.find()) {
            //匹配内容,文本,放到 matcher.group(0)
            System.out.println("找到:" + matcher.group(0));
        }
    }
}

1. 字符匹配符

符号含义示例解释
[ ]可接收的字符列表[efgh]e/f/g/h 中的任何一个字符
[^]不接收的字符列表[^abc]除 a、b、c之外的任意一个字符,包括数字和特殊符号
-连字符A-Z任意单个大写字母
.匹配除\n以外的任何字符a…b以a开头,以b结尾,中间2个任意 如 aabb,aa1b,a23b,a#%b
\\d匹配单个数字字符,等价于[0-9]\\d{3}(\\d)?包含3个、4个数字的字符串 如 123,1234
\\D匹配单个非数字字符,等价于[^0-9]\\D(\\d)*以非数字开头,后接任意个数字字符串 如 a123,a
\\w匹配单个数字、大小写字母字符、下划线,等价于[0-9a-zA-Z_]\\d{3}\\w{4}以3个数字开头,长度为7的数字字符串 如 123abcd,12345PR
\\W匹配单个非数字、大小写字母字符,等价于[^0-9a-zA-Z_]\\W+\\d{2}以至少1个非数字字母字符开头,2个数字结尾的字符串 如 #12,#A#12
\\s匹配任何空白字符(空格、制表符)
\\S匹配任何非空白字符,与\\s相反

示例代码:

import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Regexp_03 {

    @Test
    public void test() {
        String content = "abcdefABC. 123(";
        //String regStr= "[a-z]"; //匹配 a-z之间的任意一个字符
        //String regStr= "[^a-z]"; //匹配 不在a-z之间的任意一个字符
        //String regStr= "abc"; //匹配 abc  默认区分大小写

        //(?i)abc 表示 abc 都不区分大小写
        //a(?i)bc 表示 bc 不区分大小写
        //a((?i)b)c 表示只有 b 不区分大小写
        //还可以写 Pattern pattern = Pattern.compile(regStr,Pattern.CASE_INSENSITIVE); 设置不区分
        //String regStr = "(?i)abc";

        //String regStr = "[A-Z]"; //匹配 A-Z 之间的任意一个字符
        //String regStr = "[^A-Z]"; //匹配 不在A-Z 之间的任意一个字符
        //String regStr = "[0-9]"; //匹配 0-9 之间的任意一个字符
        //String regStr = "[^0-9]"; //匹配 不在0-9 之间的任意一个字符

        //String regStr = "\\s"; //匹配空格,制表符
        String regStr = "\\S"; //匹配非空格,非制表符
        
        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println("找到:" + matcher.group(0));
        }
    }
}

2. 选择匹配符

符号含义示例解释
|匹配’|'之前或之后的表达式ab|bcab或者bc
import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * @Author: mei_ming
 * @DateTime: 2022/6/9 7:22
 * @Description: 选择匹配符
 */
public class Regexp_04 {
    @Test
    public void test() {
        String content = "abcdacdv";
        String regStr = "ab|cd"; //

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println("找到:" + matcher.group(0));
        }
    }
}

3. 限定符

符号含义示例解释
*指定字符重复0次或n次(abc)*仅包含任意个abc的字符 如 abc、abcabcabc
+指定字符重复1次或n次m+(abc)*以至少1个m开头,后接任意个abc的字符 如 m、mabc、mabcabcabc
?指定字符重复0次或1次m+abc?以至少1个m开头,后接ab或abc的字符串 如mab、mabc、mmab、mmabc
{n}只能输入n个字符[abcd]{3}由abcd中的字母组成的任意长度为3的字符串 如abc、adc、acd
{n,}指定至少n个字符[abcd]{3,}由abcd中的字母组成的任意长度不小于3的字符串 如abc、adcc、acdasc
{n,m}指定至少n个但不多于m个字符[abcd]{3,5}由abcd中的字母组成的任意长度不小于3,不大于5的字符串 如abc、adcc、acdas

import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Author: mei_ming
 * @DateTime: 2022/6/9 7:22
 * @Description: 限定符
 */
public class Regexp_05 {
    @Test
    public void test() {
        String content = "a1111111aaaaa";
        //a{3},1{4},\\d{2}
        //String regStr = "a{3}"; // 匹配 aaa
        //String regStr = "1{4}"; // 匹配 1111
        //String regStr = "\\d{2}"; // 匹配 11、11、11 任意两个数字

        //a{3,4},1{4,5},\\d{2,5}

        //细节:java匹配默认贪婪匹配,尽可能匹配多的
        //String regStr="a{3,4}"; //理论上匹配 aaa 或 aaaa ,实际匹配 aaaa
        //String regStr="1{4,5}"; //理论上匹配 1111 或 11111 ,实际匹配 11111
        //String regStr="\\d{2,5}"; //理论上匹配 2位,3位,4位,5位数字 ,实际匹配 11111,11

        //1+
        //String regStr="1+"; //理论上匹配 1个1或n个1 ,实际匹配 1111111 ,符合贪婪匹配
        //String regStr="\\d+"; //理论上匹配 1个数字或n个数字 ,实际匹配 1111111

        //1*
        //String regStr="1*"; //理论上匹配 0个1或n个1

        //?
        String regStr="a1?"; //理论上匹配 a 或 a1

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println("找到:" + matcher.group(0));
        }
    }
}


4. 定位符

符号含义示例解释
^指定起始字符^[0-9]+[a-z]*以至少1个数字开头,后接任意个小写字母的字符 如123,123a
$指定结束字符^[0-9]+\\-[a-z]+$以至少1个数字开头,后接- 再加上至少1个小写字母的字符 如 123-abc
\\b匹配目标字符串的边界ma\\bmaenma ma 会匹配第二、三个ma
\\B匹配目标字符串的非边界ma\\B与\\b相反 maenma ma 会匹配第一个ma
{n,}指定至少n个字符[abcd]{3,}由abcd中的字母组成的任意长度不小于3的字符串 如abc、adcc、acdasc
{n,m}指定至少n个但不多于m个字符[abcd]{3,5}由abcd中的字母组成的任意长度不小于3,不大于5的字符串 如abc、adcc、acdas
import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * @Author: mei_ming
 * @DateTime: 2022/6/9 7:22
 * @Description: 定位符
 */
public class Regexp_06 {
    @Test
    public void test() {
        String content = "123-abc";
        //以至少1个数字开头,至少一个小写字母结束的字符串
        String  regStr="^[0-9]+\\-[a-z]+$";

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println("找到:" + matcher.group(0));
        }
    }

    @Test
    public void test2(){
        String content = "maenming enma enmingma";
        //表示匹配边界的ma[这里的边界是指:被匹配的字符串最后, 也可以是空格的子字符串的后面]
        //String  regStr="ma\\b";  //找到后两个ma

        //  \\B 与 \\b相反
        String  regStr="ma\\B";  //找到第一个ma

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println("找到:" + matcher.group(0));
        }
    }
}

5. 分组组合 、反向引用符

  1. 常用分组
常用分组构造形式说明
(pattern)非命名捕获。捕获匹配的子字符串。编号为0的第一个捕获是由整个正则表达式模式匹配的文本,其他捕获结果则根据左括号的顺序从1开始自动编号
(?<name>pattern)命名捕获。捕获匹配的子字符串。匹配的分组可以按照名字来访问也可以按照编号
import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * @Author: mei_ming
 * @DateTime: 2022/6/9 7:22
 * @Description: 捕获分组
 */
public class Regexp_07 {
    @Test
    public void test() {
        String content = "1234abcd2234";
        //matcher.group(0) 存放匹配到的全部子串
        //matcher.group(1) 存放第一个分组
        //......
        String  regStr="(\\d\\d)(\\d)(\\d)";

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println("找到:" + matcher.group(0));
            System.out.println("第1个分组:"+matcher.group(1));
            System.out.println("第2个分组:"+matcher.group(2));
            System.out.println("第3个分组:"+matcher.group(3));
        }
    }

    @Test
    public void test2(){
        String content = "1234abcd2234";
        //matcher.group(0) 存放匹配到的全部子串
        //matcher.group(1) 存放第一个分组
        //......
        //还可以按照matcher.group("g1") 获取分组
        String  regStr="(?<g1>\\d\\d)(?<g2>\\d\\d)";

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println("找到:" + matcher.group(0));
            System.out.println("分组1:" + matcher.group(1));
            System.out.println("分组1(name):" + matcher.group("g1"));
            System.out.println("分组2:" + matcher.group(2));
            System.out.println("分组2(name):" + matcher.group("g2"));
        }
    }
}

  1. 特殊分组(不能按group(编号) 取值)
常用分组构造形式说明
(?:pattern)匹配pattern但不捕获该匹配的子表达式,即他是一个非捕获匹配 ,如 industr(?:y|ies) 等价于 industry|industries
(?=pattern)一个非捕获匹配 ,如 windows(?=95|98|2000) 匹配的是 windows 2000 的windows 而不匹配windows 3.1的windows
(?!pattern)一个非捕获匹配 ,如 windows(?!95|98|2000) 匹配的是 windows 3.1 的windows 而不匹配windows 2000的windows
import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Author: mei_ming
 * @DateTime: 2022/6/9 7:22
 * @Description: 非捕获分组
 */
public class Regexp_08 {
    //(?: )
    @Test
    public void test() {
        String content = "hi小明同学 hi小李同学 hi小黄同学";

        //String  regStr="小明同学|小李同学|小黄同学";
        //等价于
        String  regStr="小(?:明|李|黄)同学";//不能捕获 matcher.group(1)

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println("找到:" + matcher.group(0));
        }
    }

    //(?= )
    @Test
    public void test2() {
        String content = "hi同学小明 hi同学小李 hi同学小黄";

        String  regStr="同学(?=小明|小李)";//匹配到的是小明or小李 的 "同学"

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println("找到:" + matcher.group(0));
        }
    }

    //(?! )
    @Test
    public void test3() {
        String content = "hi同学小明 hi同学小李 hi同学小黄";

        String  regStr="同学(?!小明|小李)";//匹配到的不是小明or小李 的 "同学"

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println("找到:" + matcher.group(0));
        }
    }
}

非贪婪匹配

import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * @Author: mei_ming
 * @DateTime: 2022/6/9
 * @Description: 非贪婪匹配
 */
public class Regexp_09 {
    //(?: )
    @Test
    public void test() {
        String content = "a11111111aaa";

        //String  regStr="\\d+";//默认贪婪匹配  返回 11111111
        String  regStr="\\d+?";  //非贪婪匹配   返回 1,1,1,1,1,1,1,1
        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println("找到:" + matcher.group(0));
        }
    }
}

6.特殊字符


三个常用类

java.util.regex 包下主要包括3个类 Pattern 、Matcher、PatternSyntaxException

Pattern

pattern对象是一个正则表达式对象。Pattern类没有公共构造方法。要创建一个Pattern对象,调用其公共静态方法,返回一个Pattern对象,该方法接受一个正则表达式作为它的第一个参数,比如:Pattern pattern = Pattern.compile(String regex)。

import org.junit.Test;
import java.util.regex.Pattern;

/**
 * @Author: mei_ming
 * @DateTime: 2022/6/11 10:38
 * @Description: 演示matches方法,用于整体匹配,在验证输入的字符串是否满足条件使用,用于简化开发
 */
public class PatternMethod {

    @Test
    public void test(){
        String content = "hello world";
        //String regStr="hello";  //false
        String regStr = "hello.*";  //true

        boolean matches = Pattern.matches(regStr, content);
        System.out.println("整体匹配= "+matches);
    }
}

Matcher

Matcher 对象是对输入字符串进行解释和匹配的引擎。与Pattern类一样,Matcher也没有公共构造方法。你需要调用Pattern对象的matcher()返回一个Matcher对象。

import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * @Author: mei_ming
 * @DateTime: 2022/6/11 13:44
 * @Description: Matcher中的方法
 */
public class MatcherMethod {

    @Test
    public void test(){
        String content = "hello world ,hello mei_ming";
        String regStr="hello";
        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println("------------------");
            System.out.println("起始位置:"+matcher.start());
            System.out.println("结束位置:"+matcher.end());
            System.out.println("找到:" + matcher.group(0));
            System.out.println("找到:"+content.substring(matcher.start(),matcher.end())); //等同于 group(0)
        }
    }

    //整体匹配
    @Test
    public void test2(){
        String content = "hello world ,hello mei_ming";
        String regStr="hello.*";
        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        //整体匹配
        System.out.println(matcher.matches());  //true
    }

    //替换
    @Test
    public void test3(){
        String content = "hello world ,hello mei_ming";
        //替换成regStr的值
        String regStr="hello";
        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        String newContent = matcher.replaceAll("hi");
        System.out.println("返回的字符串:"+newContent);
        System.out.println("原来的字符串:"+content);
    }
}


PatternSyntaxException

PatternSyntaxException是一个非强制异常类,他表示一个正则表达式模式中的语法错误


反向引用

  1. 分组:用圆括号组成一个比较复杂的匹配模式,称为一个分组或一个子表达式
  2. 捕获:把正则表达式中的分组内容,保存到内存中以数字编号或显式命名的组里,方便后面引用,从左向右,以分组的左括号为标志,第一个出现分组为1…,整体分组为0
  3. 反向引用:圆括号的内容被捕获后,可以在这个括号后被使用,从而写出一个比较实用的匹配模式,成为反向引用,内部反向引用 \\分组号 ,外部反向引用: $分组号
import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * @Author: mei_ming
 * @DateTime: 2022/6/11 14:05
 * @Description: 反向引用
 */
public class Regexp_11 {
    @Test
    public void test(){
        String content = "abc1221 33abcd144444acbc 5566 ";
        //匹配两个连续相同的数
        //String regStr = "(\\d)\\1";

        //匹配五个连续相同的数
        //String regStr = "(\\d)\\1{4}";

        //匹配abba这样的四位数
        String regStr = "(\\d)(\\d)\\2\\1";

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println("找到:" + matcher.group(0));
        }
    }

    @Test
    public void test2(){
        String content = "12345-333999666";

        //匹配 12345-333999666 这样的数   -左边5位数随机 -右边9位数 aaabbbccc
        String regStr = "\\d{5}-(\\d)\\1{2}(\\d)\\2{2}(\\d)\\3{2}";

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println("找到:" + matcher.group(0));
        }
    }
}


原理

import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Author: mei_ming
 * @DateTime: 2022/6/8 20:59
 * @Description: 正则底层原理
 */
public class RegTheory {

    //匹配无分组的情况
    @Test
    public void test1(){
        String content="2000年5月,JDK1.3、JDK1.4和J2SE1.3相继发布,几周后其获得了Apple公司Mac OS X的工业标准的支持。2001年9月24日," +
                "J2EE1.3发布。2002年2月26日,J2SE1.4发布。自此Java的计算能力有了大幅提升" +
                ",与J2SE1.3相比,其多了近62%的类和接口。在这些新特性当中,还提供了广泛的XML支持、" +
                "安全套接字(Socket)支持(通过SSL与TLS协议)、全新的I/OAPI、正则表达式、日志与断言。" +
                "2004年9月30日,J2SE1.5发布,成为Java语言发展史上的又一里程碑。为了表示该版本的重要性," +
                "J2SE 1.5更名为Java SE 5.0(内部版本号1.5.0),代号为“Tiger”,Tiger包含了从1996年发布" +
                "1.0版本以来的最重大的更新,其中包括泛型支持、基本类型的自动装箱、改进的循环、枚举类型、格式化I/O及可变参数。";

        //1. 创建Pattern对象,
        //提取文章中的四个数字
        //   \\d 表示一个任意的数字
        Pattern pattern = Pattern.compile("\\d\\d\\d\\d");
        //2. 创建匹配器对象
        // 理解 matcher 匹配器按照pattern模式对象,到content文本中去匹配
        // 找到则返回true, 否则返回false
        Matcher matcher = pattern.matcher(content);
        //3. 可以开始循环匹配
        /**
         * matcher.find() 完成的任务
         * 1. 根据指定的规则,定位满足规则的子字符串(比如2000)
         * 2. 找到后,将 子字符串的开始索引记录到matcher对象属性  int[] groups; 中
         *    赋值  groups[0] = 0 即开始位置
         *         groups[1] = 4 即子字符串结束位置 +1
         * 3. 同时记录oldLast的值为4,作为下一次执行find的位置
         *
         * matcher.group(0) 完成的任务
         *
         * 源码:
         * public String group(int group) {
         *         if (first < 0)
         *             throw new IllegalStateException("No match found");
         *         if (group < 0 || group > groupCount())
         *             throw new IndexOutOfBoundsException("No group " + group);
         *         if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
         *             return null;
         *         return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
         * }
         *
         * 1. getSubSequence 方法 返回从 groups[group * 2]到 groups[group * 2 + 1] 的子串 ,即group=0
         *    根据groups[0]=0,groups[1]=4 的记录的位置,从content开始截取子字符串
         *     就是[0,4)的位置上的字符
         *
         * 若再次执行, groups[0] = 65 , groups[1] = 69 , ordLast = 69
         * getSubSequence(65,69) 返回 2001
         */
        while(matcher.find()){
            //匹配内容,文本,放到 matcher.group(0)
            System.out.println("找到:" + matcher.group(0));
        }
    }

    //有分组的情况
    @Test
    public void test2(){
        String content="2000年5月,JDK1.3、JDK1.4和J2SE1.3相继发布,几周后其获得了Apple公司Mac OS X的工业标准的支持。2001年9月24日," +
                "J2EE1.3发布。2002年2月26日,J2SE1.4发布。自此Java的计算能力有了大幅提升" +
                ",与J2SE1.3相比,其多了近62%的类和接口。在这些新特性当中,还提供了广泛的XML支持、" +
                "安全套接字(Socket)支持(通过SSL与TLS协议)、全新的I/OAPI、正则表达式、日志与断言。" +
                "2004年9月30日,J2SE1.5发布,成为Java语言发展史上的又一里程碑。为了表示该版本的重要性," +
                "J2SE 1.5更名为Java SE 5.0(内部版本号1.5.0),代号为“Tiger”,Tiger包含了从1996年发布" +
                "1.0版本以来的最重大的更新,其中包括泛型支持、基本类型的自动装箱、改进的循环、枚举类型、格式化I/O及可变参数。";

        //1. 创建Pattern对象,
        //提取文章中的四个数字
        //   \\d 表示一个任意的数字
        Pattern pattern = Pattern.compile("(\\d\\d)(\\d\\d)");
        //2. 创建匹配器对象
        // 理解 matcher 匹配器按照pattern模式对象,到content文本中去匹配
        // 找到则返回true, 否则返回false
        Matcher matcher = pattern.matcher(content);
        //3. 可以开始循环匹配
        /**
         * matcher.find() 完成的任务
         * 1. 根据指定的规则,定位满足规则的子字符串(比如2000)
         * 2. 找到后,将 子字符串的开始索引记录到matcher对象属性  int[] groups; 中
         *    2.1 赋值  groups[0] = 0 即开始位置
         *             groups[1] = 4 即子字符串结束位置 +1
         *
         *    2.2 接着赋值 groups[2]=0, groups[3]=2  记录第一个分组()匹配到的字符串
         *    2.3 接着赋值 groups[4]=2, groups[5]=4  记录第二个分组()匹配到的字符串
         *
         * 3. 同时记录oldLast的值为4,作为下一次执行find的位置
         *
         * matcher.group(0) 完成的任务
         *
         * 源码:
         * public String group(int group) {
         *         if (first < 0)
         *             throw new IllegalStateException("No match found");
         *         if (group < 0 || group > groupCount())
         *             throw new IndexOutOfBoundsException("No group " + group);
         *         if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
         *             return null;
         *         return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
         * }
         *
         * 1. getSubSequence 方法 返回从 groups[group * 2]到 groups[group * 2 + 1] 的子串 ,
         *    若group=0时 ,根据groups[0]=0,groups[1]=4 的记录的位置,从content开始截取子字符串
         *               就是[0,4)的位置上的字符
         *    若group=1时 ,就是groups[2]=0,groups[3]=2 的记录的位置,也就是 [0,2)
         *    若group=2时 ,就是groups[4]=2,groups[5]=4 的记录的位置,也就是 [2,4)
         *
         */
        while(matcher.find()){
            //小结:
            //1. 如果正则表达式有() 即 有分组
            //2. 取出字符串如下
            //3. group(0) : 取 匹配到的字符串
            //4. group(1) : 取 第一组的字符串
            //5. group(2) : 取 第二组的字符串
            //6. 越界则报错 throw new IndexOutOfBoundsException("No group " + group);
            System.out.println("找到:" + matcher.group(0));
            System.out.println(" 找到:" + matcher.group(1));
            System.out.println(" 找到:" + matcher.group(2));
        }
    }
}

应用实例

import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Author: mei_ming
 * @DateTime: 2022/6/11 9:34
 * @Description: 正则表达式应用实例
 */
public class Regexp_10 {

    @Test
    public void test(){
        //汉字
        //String content="中文汉字";  //满足要求
        //String regStr="^[\u0391-\uffe5]+$";

        //邮政编码
        //要求:是1-9开头的一个6位数
        //String content = "330324";
        //String regStr="^[1-9]\\d{5}$";

        // QQ号
        //要求:是1-9开头的一个5位-10位数
        //String content = "1791666142";
        //String regStr="^[1-9]\\d{4,9}$";

        // 手机号
        //要求:是以13,14,15,18 开头的11位数
        String content = "13916661421";
        String regStr="^1[3|4|5|8]\\d{9}$";
        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        if(matcher.find()){
            System.out.println("满足要求");
        }else{
            System.out.println("不满足要求");
        }
    }

    @Test
    public void test2(){
        //URL验证
        //String content = "https://baike.baidu.com/item/Java/85979?fr=aladdin";
        String content = "http://tgxmf.yxaad.com/school/dl/9607/" +
                "?source=shyx-pc&plan=3wanglianyu-DL&unit=dlzhancheng%EF%BC%8Bjavaxiangmu&" +
                "keyword=javapeixunlingjichu&e_creative=58309754528&e_keywordid=393605165955&bd_vid=11917634435375433147";
        /**
         * 验证思路:
         * 1. 匹配开头:^((https?)://)  可以是 http:// | https://
         * 2. 然后通过 ([\w-]+\.)+[\w-]+ 匹配 baike.baidu.com
         * 3. (\/[\w-?=&/%.#]*)?$ 匹配 /item/Java/85979?fr=aladdin
         */
        String regStr="^((https?)://)([\\w-]+\\.)+[\\w-]+(\\/[\\w-?=&/%.#]*)?$";
        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        if(matcher.find()){
            System.out.println("满足要求");
        }else{
            System.out.println("不满足要求");
        }
    }

    //测试 [.]
    @Test
    public void test3(){
        String content = "hello.world";
        //String regStr=".";  //匹配所有
        String regStr="[.]";  //匹配 .
        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        while(matcher.find()){
            System.out.println("找到:"+matcher.group(0));
        }
    }

	//邮箱验证 
	//matches:整体匹配
    @Test
    public void test4(){
        //只有1个@
        //@前面是用户名,可以是a-zA-Z0-9_-字符
        //@后面是域名,比如sohu.com souhu.com.cn
        String content = "1791666142@qq.com";
        String regStr= "^[\\w-]+@([a-zA-Z]+\\.)+[a-zA-Z]+$";
        if(content.matches(regStr)){
            System.out.println("符合");
        }else{
            System.out.println("不符合");
        }
    }

	//判断数字
    @Test
    public void test5(){
        //1. 验证整数和浮点数
        //2. 正数和负数
        //+1  √
        //-1  √
        //0.1  √
        //12.21  √
        //23  √
        String content = "0.234";
        String regStr= "^[-+]?([1-9]\\d*|0)(\\.\\d+)?$";
        if(content.matches(regStr)){
            System.out.println("符合");
        }else{
            System.out.println("不符合");
        }
    }
    
	//验证URL 取协议、域名等
    @Test
    public void test6(){
        //协议、域名、端口、资源
        String content = "http://www.baidu.com:8080/admin/index.jsp";
        String regStr= "^([a-zA-Z]+)://([a-zA-Z.]+):(\\d+)[\\w-/]*/([\\w.]+)$";
        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);
        if(matcher.find()){
            System.out.println("匹配成功:"+matcher.group(0));
            System.out.println("协议:"+matcher.group(1));
            System.out.println("域名:"+matcher.group(2));
            System.out.println("端口:"+matcher.group(3));
            System.out.println("资源:"+matcher.group(4));
        }else{
            System.out.println("不符合");
        }
    }
}

个人自学用笔记,欢迎纠错

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值