【Java基础】14.正则表达式

文章目录


前言

正则表达式定义了字符串的模式。

正则表达式可以用来搜索、编辑或处理文本。

正则表达式并不仅限于某一种语言,但是在每种语言中有细微的差别。

Java 提供了 java.util.regex 包,通过 java.util.regex 包中的类和方法,我们可以在 Java 程序中使用正则表达式进行字符串处理。

一、java.util.regex 包

java.util.regex 包是 Java 标准库中用于支持正则表达式操作的包。

java.util.regex 包主要包括以下三个类:

  • Pattern 类:
    pattern 对象是一个正则表达式的编译表示。Pattern 类没有公共构造方法。要创建一个 Pattern 对象,你必须首先调用其公共静态编译方法,它返回一个 Pattern 对象。该方法接受一个正则表达式作为它的第一个参数。
  • Matcher 类:
    Matcher 对象是对输入字符串进行解释和匹配操作的引擎。与Pattern 类一样,Matcher 也没有公共构造方法。你需要调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象。
  • PatternSyntaxException:
    PatternSyntaxException 是一个非强制异常类,它表示一个正则表达式模式中的语法错误。

二、语法

根据 Java Language Specification 的要求,Java 源代码的字符串中的反斜线被解释为 Unicode 转义或其他字符转义。因此必须在字符串字面值中使用两个反斜线 // ,表示正则表达式受到保护,不被 Java 字节码编译器解释。

正则表达式是由字符和特殊字符组成的模式,用于匹配和处理文本。以下是一些常用的正则表达式特殊字符:

  • .:匹配任意单个字符。
  • *:匹配前面的字符零次或多次。
  • +:匹配前面的字符一次或多次。
  • ?:匹配前面的字符零次或一次。
  • \d:匹配数字字符。
  • \w:匹配单词字符(字母、数字、下划线)。
  • \s:匹配空白字符(空格、制表符等)。

除了特殊字符外,我们还可以使用一些限定符来指定匹配的次数:

  • {n}:匹配前面的字符恰好 n 次。
  • {n,}:匹配前面的字符至少 n 次。
  • {n,m}:匹配前面的字符至少 n 次,最多 m 次。

实例:

java 复制代码
public class RegexDemo1 {
    public static void main(String[] args) {
        // 校验qq号码,必须全部数字 6 - 20位
        System.out.println("----不用正则表达式----");
        System.out.println("251425998:" + checkQQ("251425998")); // 251425998:true
        System.out.println("2514259a98:" + checkQQ("2514259a98")); // 2514259a98:false
        System.out.println("null:" + checkQQ(null)); // null:false
        System.out.println("2344:" + checkQQ("2344")); // 2344:false

        System.out.println("----用正则表达式----");
        System.out.println("251425998:" + checkQQ2("251425998")); // 251425998:true
        System.out.println("2514259a98:" + checkQQ2("2514259a98")); // 2514259a98:false
        System.out.println("null:" + checkQQ2(null)); // null:false
        System.out.println("2344:" + checkQQ2("2344")); // 2344:false
    }

    /**
     * 正则表达式,必须全部是数字,6 - 20位
     * @param qq
     * @return
     */
    public static boolean checkQQ2(String qq) {
        // \\d代表全数字,{6,20}代表6-20位
        return qq != null && qq.matches("\\d{6,20}");
    }


    /**
     * 正则表达式,必须全部是数字,6 - 20位
     * @param qq
     * @return
     */
    public static boolean checkQQ(String qq) {
        // 1、判断qq号码的长度是否满足要求
        if (qq == null || qq.length() < 6 || qq.length() > 20) {
            return false;
        }
        // 2、判断qq中是否全部是数字,不是返回false
        for (int i = 0; i < qq.length(); i++) {
            // 获取每位字符
            char ch = qq.charAt(i);
            // 判断这个字符是否不是数字,不是数字直接返回false
            if (ch < '0' || ch > '9') {
                return false;
            }
        }
        return true; // 肯定合法了!
    }

}

编译运行结果如下:

java 复制代码
----不用正则表达式----
251425998:true
2514259a98:false
null:false
2344:false
----用正则表达式----
251425998:true
2514259a98:false
null:false
2344:false

三、步骤

在 Java 中使用正则表达式,通常需要经过以下几个步骤:

  1. 创建一个正则表达式的模式(Pattern)对象。
  2. 使用模式对象创建一个匹配器(Matcher)对象。
  3. 调用匹配器对象的方法进行匹配、查找或替换操作。
  4. 根据需要处理匹配结果。
java 复制代码
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @ClassName: RegexDemo2
 * @Description: 使用正则表达式步骤
 * @author: Zh
 * @date: 2024/4/13 17:03
 */
public class RegexDemo2 {
    public static void main(String[] args) {

        String s1 = "Hello, World! This is a test string.";
        String s2 = "test";
        String s3 = ".*test.*";

        // 1.创建一个正则表达式的模式(Pattern)对象
        Pattern p = Pattern.compile(s2);

        // 2.使用模式对象创建一个匹配器(Matcher)对象
        Matcher m = p.matcher(s1);

        // 3.调用匹配器对象的方法进行匹配、查找或替换操作
        if (m.find()) {
            // 4.根据需要处理匹配结果
            System.out.println("找到匹配的字符串");
        } else {
            System.out.println("未找到匹配的字符串");
        }

        System.out.println("用test匹配:" + Pattern.matches(s2, s1)); // 用test匹配:false
        // .匹配除"\r\n"之外的任何单个字符
        // *零次或多次匹配前面的字符或子表达式
        System.out.println("用.*test.*匹配:" + Pattern.matches(s3, s1)); // 用.*test.*匹配:true
    }
}

编译运行结果如下:

java 复制代码
找到匹配的字符串
用test匹配:false
用.*test.*匹配:true

四、Pattern类与Matcher类

1.matches( )

java 复制代码
boolean flag = str.matches(regex);

快速判断能否在str中找到regex。

2.split( )

java 复制代码
String[ ] ss = s.split(regex);

用regex把字符串分隔开来,返回String数组。

3.find( )

java 复制代码
while(matcher.find(i)){
i++;
}

Matcher.find( )的功能是发现CharSequence里的,与pattern相匹配的多个字符序列。

4.group

java 复制代码
A(B(C))D 里面有三个组:
group(0) 是 ABCD
group(1) 是 BC
group(2) 是 C
形式为 matcher.group( )

5.start( )和end( )

如果匹配成功,start( )会返回此次匹配的开始位置,end( )会返回此次匹配的结束位置,即最后一个字符的下标加一。

如果之前的匹配不成功(或者没匹配),那么无论是调用start( )还是end( ),都会引发一 个IllegalStateException。

java 复制代码
matcher.start( );
matcher.end( );

6.replace替换

replaceFirst(String replacement)将字符串里,第一个与模式相匹配的子串替换成replacement。

replaceAll(String replacement),将输入字符串里所有与模式相匹配的子串全部替换成replacement。

java 复制代码
String result = s.replaceAll(regex,ss);
String result = s.replaceFirst(regex,ss);

7.reset( )

用reset( )方法可以给现有的Matcher对象配上个新的CharSequence。

如果不给参数,reset( )会把Matcher设到当前字符串的开始处。

java 复制代码
m.reset("java");

实例:

java 复制代码
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @ClassName: RegexDemo04
 * @Description: 正则表达式Pattern类与Matcher类
 * @author: Zh
 * @date: 2024/4/13 15:23
 */
public class RegexDemo04 {
    public static void main(String[] args) {
        String names = "小路dhdfhdf342蓉儿43fdffdfbjdfaf小何";
        // 创建一个正则表达式的模式(Pattern)对象
        Pattern pattern = Pattern.compile("\\w+");
        // 使用模式对象创建一个匹配器(Matcher)对象
        Matcher matcher = pattern.matcher(names);

        // 1.boolean flag = str.matches(regex);
        // 快速判断能否在str中找到regex。
        System.out.println("1.matches:" + names.matches(".*小何.*"));

        // 2.String[ ] ss = s.split(regex);
        // 用regex把字符串分隔开来,返回String数组。
        System.out.println("----2.split----");
        String[] arrs = names.split("\\w+");
        for (int i = 0; i < arrs.length; i++) {
            System.out.println(arrs[i]);
        }

        // 3.replaceFirst(String replacement)
        // 将字符串里,第一个与模式相匹配的子串替换成replacement。
        String names1 = names.replaceFirst("\\w+", "  ");
        System.out.println("3.replaceFirst:" + names1);

        // 4.replaceAll(String replacement)
        // 将输入字符串里所有与模式相匹配的子串全部替换成replacement。
        String names2 = names.replaceAll("\\w+", "  ");
        System.out.println("4.replaceAll:" + names2);

        // 5.Matcher.find( )
        // 发现CharSequence里的,与pattern相匹配的多个字符序列。
        while (matcher.find()) {
            // 6.如果匹配成功,start( )会返回此次匹配的开始位置。
            // 7.如果匹配成功,end( )会返回此次匹配的结束位置,即最后一个字符的下标加一。
            System.out.print("6.start index: " + matcher.start()  + " ");
            System.out.print("7.end index: " + matcher.end() + " ");
            System.out.println(matcher.group());
        }

    }

}

编译运行结果如下:

java 复制代码
1.matches:true
----2.split----
小路
蓉儿
小何
3.replaceFirst:小路  蓉儿43fdffdfbjdfaf小何
4.replaceAll:小路  蓉儿  小何
6.start index: 2 7.end index: 12 dhdfhdf342
6.start index: 14 7.end index: 28 43fdffdfbjdfaf

五、正则表达式的应用

1.校验:手机号码

java 复制代码
String regex = "^1[3456789]\\d{9}$"; 

这个正则表达式用于匹配中国大陆地区的手机号码格式。我们可以逐步分解这个正则表达式以理解其含义:

  1. ^:表示字符串的开始。
  2. 1:匹配手机号码的第一位数字,即"1"。
  3. [3456789]:匹配手机号码的第二位数字,这里限定为"3"、"4"、"5"、"6"、"7"、"8"或"9"。
  4. \d{9}:匹配接下来的9位数字。\d 是一个转义序列,用于匹配任何数字(相当于 [0-9])。{9} 表示前面的模式(在这里是 \d,即一个数字)需要重复9次。
  5. $:表示字符串的结束。

2.校验:电子邮箱

java 复制代码
String regex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$"; 

该正则表达式用于匹配电子邮件地址的格式。我们可以逐步分解这个正则表达式以理解其含义:

  1. ^:表示字符串的开始。
  2. [A-Za-z0-9+_.-]+:这是一个字符类,匹配一个或多个(由 + 指定)在括号内列出的字符。这包括:
    A-Z:任何大写字母。
    a-z:任何小写字母。
    0-9:任何数字。
    +:加号字符。
    _:下划线字符。
    .:点字符。
    -:连字符字符(注意,在这个字符类中,. 和 - 是特殊字符,所以它们本身也需要被匹配)。
    这个部分匹配电子邮件地址的用户名部分,用户名可以包含字母、数字、加号、下划线、点或连字符。
  3. @:匹配电子邮件地址中的 @ 符号。
  4. [A-Za-z0-9.-]+:另一个字符类,与之前的类似,但这里仅包含字母、数字、点和连字符。这匹配电子邮件地址的域名部分。域名可以包含字母、数字、点或连字符。
  5. $:表示字符串的结束。

3.校验:身份证号

java 复制代码
String regex = "^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}([0-9]|X|x)$";  

这个正则表达式用于匹配中国大陆地区的身份证号码格式。我们可以逐步分解这个正则表达式以理解其含义:

  1. ^:表示字符串的开始。
  2. [1-9]\d{5}:匹配身份证号码的前六位地区代码。其中 [1-9] 匹配第一位数字(地区代码的第一位不能为0),\d{5} 匹配接下来的五位数字。
  3. (18|19|20)\d{2}:匹配出生年份。(18|19|20) 匹配"18"、"19"或"20",\d{2} 匹配接下来的两位数字,即年份的后两位。
  4. ((0[1-9])|(10|11|12)):匹配出生月份。(0[1-9]) 匹配"01"到"09",(10|11|12) 匹配"10"、"11"或"12",即匹配1到12月。
  5. (([0-2][1-9])|10|20|30|31):匹配出生日期。([0-2][1-9]) 匹配"01"到"29",10|20|30|31 匹配"10"、"20"、"30"或"31",即匹配1到31日。需要注意的是,这个正则并没有考虑到每个月具体的天数差异(比如2月可能只有28或29天),因此它只是一个大致的匹配。
  6. \d{3}:匹配顺序码,即身份证号码中的接下来三位数字。
  7. ([0-9]|X|x)$:匹配校验码。[0-9] 匹配任何一位数字,X|x 匹配大写或小写的"X"。
  8. $ 表示字符串的结束。

实例

java 复制代码
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @ClassName: RegexTest3
 * @Description: 正则表达式应用
 * 手机号、邮箱、身份证号码
 * @author: Zh
 * @date: 2024/4/13 20:53
 */
public class RegexTest3 {
    public static void main(String[] args) {
        System.out.println("----校验:手机号码----");
        String[] mobileNumbers = {
                "13800138000",
                "14725836900",
                "12345678900", // 无效的手机号,位数不够
                "123456789012", // 无效的手机号,位数太多
                "abc1234567890" // 无效的手机号,包含非数字字符
        };

        for (String mobileNumber : mobileNumbers) {
            if (isValidMobileNumber(mobileNumber)) {
                System.out.println(mobileNumber + ":是有效的手机号。");
            } else {
                System.out.println(mobileNumber + ":是无效的手机号。");
            }
        }

        System.out.println("----校验:电子邮箱----");
        String[] emailAddresses = {
                "test@example.com",
                "example@gmail.com",
                "invalid@", // 无效的邮箱,缺少域名部分
                "@example.com", // 无效的邮箱,缺少用户名部分
                "test.email@example", // 无效的邮箱,缺少顶级域名部分
                "test..email@example.com", // 无效的邮箱,用户名中有多个点
                "test@example..com", // 无效的邮箱,域名中有多个点
                "test@example.com.", // 无效的邮箱,以点结尾
                "test@.com" // 无效的邮箱,用户名或域名部分缺失
        };

        for (String email : emailAddresses) {
            if (isValidEmail(email)) {
                System.out.println(email + ":是有效的邮箱地址。");
            } else {
                System.out.println(email + ":是无效的邮箱地址。");
            }
        }

        System.out.println("----校验:身份证号----");
        String[] idCards = {
                "11010519491231002X", // 有效的身份证号
                "123456789012345678", // 无效的身份证号,位数不对
                "11010519491231002A", // 无效的身份证号,最后一位不是数字或X
                "11010519491231002",  // 无效的身份证号,位数不够
                "110105194912310021"  // 无效的身份证号,位数太多
        };

        for (String idCard : idCards) {
            if (isValidIDCardFormat(idCard)) {
                System.out.println(idCard + ":是有效的身份证号格式。");
            } else {
                System.out.println(idCard + ":是无效的身份证号格式。");
            }
        }

    }

    /**
     * 校验:手机号码
     * @param mobileNumber
     * @return
     */
    public static boolean isValidMobileNumber(String mobileNumber) {
        // 中国手机号的正则表达式
        // 1开头,第二位可以是3456789,后面跟着9位数字
        String regex = "^1[3456789]\\d{9}$";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(mobileNumber);
        return matcher.matches();
    }

    /**
     * 校验:邮箱
     * @param email
     * @return
     */
    public static boolean isValidEmail(String email) {
        // 邮箱地址的正则表达式
        // 这个正则表达式不是最严格的,但能够匹配大多数常见的邮箱地址格式
        String regex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(email);
        return matcher.matches();
    }

    /**
     * 校验:身份证号码
     * @param idCard
     * @return
     */
    public static boolean isValidIDCardFormat(String idCard) {
        // 身份证号码的正则表达式,17位数字加上一位数字或X
        String regex = "^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}([0-9]|X|x)$";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(idCard);
        return matcher.matches();
    }

}

编译运行结果如下:

java 复制代码
----校验:手机号码----
13800138000:是有效的手机号。
14725836900:是有效的手机号。
12345678900:是无效的手机号。
123456789012:是无效的手机号。
abc1234567890:是无效的手机号。
----校验:电子邮箱----
test@example.com:是有效的邮箱地址。
example@gmail.com:是有效的邮箱地址。
invalid@:是无效的邮箱地址。
@example.com:是无效的邮箱地址。
test.email@example:是有效的邮箱地址。
test..email@example.com:是有效的邮箱地址。
test@example..com:是有效的邮箱地址。
test@example.com.:是有效的邮箱地址。
test@.com:是有效的邮箱地址。
----校验:身份证号----
11010519491231002X:是有效的身份证号格式。
123456789012345678:是无效的身份证号格式。
11010519491231002A:是无效的身份证号格式。
11010519491231002:是无效的身份证号格式。
110105194912310021:是有效的身份证号格式。
相关推荐
Ch.yang2 分钟前
【Spring】 Bean 注入 HttpServletRequest 能保证线程安全的原理
java·spring·代理模式
web150850966413 分钟前
基于Mysql、JavaScript、PHP、ajax开发的MBTI性格测试网站(前端+后端)
java
昙鱼11 分钟前
springboot创建web项目
java·前端·spring boot·后端·spring·maven
eternal__day11 分钟前
数据结构(哈希表(中)纯概念版)
java·数据结构·算法·哈希算法·推荐算法
天之涯上上16 分钟前
JAVA开发 在 Spring Boot 中集成 Swagger
java·开发语言·spring boot
2402_8575834917 分钟前
“协同过滤技术实战”:网上书城系统的设计与实现
java·开发语言·vue.js·科技·mfc
白宇横流学长18 分钟前
基于SpringBoot的停车场管理系统设计与实现【源码+文档+部署讲解】
java·spring boot·后端
APP 肖提莫21 分钟前
MyBatis-Plus分页拦截器,源码的重构(重构total总数的计算逻辑)
java·前端·算法
kirito学长-Java23 分钟前
springboot/ssm太原学院商铺管理系统Java代码编写web在线购物商城
java·spring boot·后端
爱学习的白杨树24 分钟前
MyBatis的一级、二级缓存
java·开发语言·spring