第十六章《正则表达式》第4节:Matcher类

本文深入讲解了Java中Matcher类在正则表达式匹配和替换中的应用。Matcher类作为执行匹配操作的引擎,通过Pattern对象的matcher()方法创建实例。文章通过比喻解释Matcher类的工作原理,并列举了matches()、lookingAt()、find()等关键匹配方法,以及replaceFirst()、replaceAll()替换方法的使用。此外,还介绍了如何通过region()方法设定搜索范围。示例代码演示了Matcher类的各种操作,展示了在不同场景下的应用效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

16.3小节所介绍的Pattern类代表了正则表达式,它的功能不是很强,如果程序员想用正则表达式完成替换等更复杂的操作,必须使Matcher类。Matcher类也位于java.util.regex包下,使用这个类时需要用import关键字进行引入。

Java语言的官方文档把Matcher类解释为执行匹配操作的引擎,但这个解释过于抽象,不好理解。为方便读者理解,可以把Matcher类比喻成一个智能机器人,这个机器人手里拿着一个正则表达式,脚下是一个字符串。它拿着正则表达式,在脚下字符串上来回的移动,寻找能够与表达式相匹配的目标字符串。当机器人找到了目标字符串以后,可以做很多操作,例如替换操作等。需要说明:智能机器人手中拿着的正则表达式实际上就是一个Pattern类的对象,而它脚下是字符串既可以是String类对象,也可以是StringBuffer类和StringBuilder类对象。本小节将详细讲解Matcher类的使用。

16.4.1 Matcher类的匹配方法

Matcher类的构造方法不是公开的,所以程序员不能直接通过new关键字创建它的对象。创建Matcher类对象需要调用Pattern对象的matcher()方法来完成,例如:

String str = "1a";
Pattern  p = Pattern.compile("\\d\\w");
Matcher m = p.matcher(str);

从以上代码可以看到:matcher()方法的参数是一个字符串,这个字符串就是智能机器人脚下的那个字符串,所创建出的Mather类对象就会从这个字符串中完成搜索,而Pattern对象p就是智能机器人手中拿着的那个正则表达式。

Matcher类中提供了一些用于匹配目标字符串的方法,如表16-6所示。

表16-6 Matcher类的匹配方法

方法

功能

boolean matches()

测试字符串整体能否与正则表达式相匹配

boolean lookingAt()

测试字符串是不是以正则表达式所定义的结构开头

boolean find()

搜索下一个目标字符串,如能找到返回true,否则返回false

public boolean find(int start)

从索引为start的位置开始搜索目标字符串

public String group()

获得当前匹配项整体,必须在已经找到目标字符串的情况下执行此方法才有意义,否则会抛出异常

String group(int group)

获得当前匹配项中编号为group的组中的内容,必须在已经找到目标字符串的情况下执行此方法才有意义,否则会抛出异常

String start()

获得当前匹配项内容在整体字符串中的起始位置

String start(int group)

获得当前匹配项中第group组的内容在整体字符串中的起始位置

String end()

获得当前匹配项的内容最后一个字符在整体字符串中的位置+1

String end(int group)

获得当前匹配项中第group组的内容在整体字符串中的位置+1

int groupCount()

获得正则表达式中分组的个数

在表16-6所列出的这些方法中,最核心的就是find()方法。如果字符串中存在能够与正则表达式匹配的目标字符串,那么find()方法能够让智能机器人移动到这个目标字符串上,只有移动到目标字符串上,才能调用group()、start()、end()这些方法来获得这个目标字符串以及它的各项数据。而如果希望智能机器人回到初始位置,只要调用Matcher类的reset()方法就能完成。

下面的【例16_16】展示了Matcher类匹配方法的使用。

【例16_16 Matcher类的匹配方法

Exam16_16.java

import java.util.regex.*;
public class Exam16_16 {
    public static void main(String[] args) {
        String str = "abbaqwecddc";//str就是机器人脚下的字符串
        String reg = "(.)(.)\\2\\1";//表示4个字符且左右对称的结构
        Pattern p = Pattern.compile(reg);//p就是机器人手里的正则表达式
        Matcher m = p.matcher(str);//m就是智能机器人
        System.out.println("正则表达式中分组的个数:"+m.groupCount());
        System.out.println("str整体是否匹配正则表达:"+m.matches());
        int i=1;
        while (m.find()){//搜索能够匹配的目标字符串
            System.out.println("找到了第"+i+"个目标字符串!");
            System.out.println("目标字符串是:"+m.group());
            System.out.println("目标字符串中第一组的内容是:"+m.group(1));
            System.out.println("目标字符串在str中的位置:"+m.start());
            System.out.println("目标字符串最后一个字符在str中的位置"+(m.end()-1));
            i++;
        }
    }
}

【例16_16】的运行结果如图16-16所示。

图16-16【例16_16】运行结果

从图16-16可以看出:只有find()方法找到了符合匹配条件的目标字符串,才能调用group()、start()、end()这些方法来获得这个目标字符串以及它的各项数据。

16.4.2 Matcher类的替换方法

Matcher类不仅仅能够在字符串中找到匹配项,还能够把这些匹配项替换成某个字符串,完成替换操作需要用到Matcher类的替换方法,这些替换方法如表16-7所示。

表16-7 Matcher类的替换方法

方法

功能

String replaceFirst(String rep)

把字符串中第一个匹配项替换为rep,并返回替换后的字符串

String replaceAll (String rep)

把字符串中所有匹配项替换为rep,并返回替换后的字符串

Matcher appendReplacement

(StringBuffer sb, String rep)

把当前匹配项替换为rep,之后把当前匹配项替换为rep,并且把rep及其前面的内容统统添加到sb的末尾,之前添加过的内容不会重复添加

StringBuffer appendTail(StringBuffer sb)

把最后一次被替换的目标字符串后面的部分添加到sb中。

Matcher类的这些替换方法中,appendReplacement()方法也需要先调用find()方法找到一个匹配项,然后才能执行。下面的【例16_17】展示了replaceFirst()和replaceAll ()方法的作用和效果。

【例16_17 Matcher类的替换方法1

Exam16_17.java

import java.util.regex.*;
public class Exam16_17 {
    public static void main(String[] args) {
        String str = "xyzabbauvwcddc";
        String reg = "(.)(.)\\2\\1";//正则表达式定义了4字符对称结构
        Pattern p = Pattern.compile(reg);
        Matcher m = p.matcher(str);
        //替换第一个对称字符串
        String replace1 = m.replaceFirst("*");
        System.out.println(replace1);
        //替换所有的对称字符串
        String replace2 = m.replaceAll("*");
        System.out.println(replace2);
    }
}

【例16_17】的运行结果如图16-17所示。

图16-17【例16_17】运行结果

replaceAll ()方法只能把满足匹配条件的目标字符串全部进行替换,如果希望把第1、3、5、7...等奇数号的目标字符串进行替换,就必须使用appendReplacement()和appendTail()方法实现,下面的【例16_18】展示了appendReplacement()和appendTail()方法的作用和效果。

【例16_18 Matcher类的替换方法2

Exam16_18.java

import java.util.regex.*;
public class Exam16_18 {
    public static void main(String[] args) {
        String str = "123456789xyz";
        String reg = "\\d";
        Pattern p = Pattern.compile(reg);
        Matcher m = p.matcher(str);
        int i=0;
        StringBuffer sb = new StringBuffer();
        while (m.find()){//持续搜索目标字符串
            if(++i%2==1){//仅有奇数号的目标字符串被替换
                //替换后把前面的部分加入sb末尾
                m.appendReplacement(sb,"*");
            }
        }
        //把最后一次被替换的目标字符串后面的部分添加到sb中
        m.appendTail(sb);
        System.out.println(sb);
    }
}

【例16_18】的运行结果如图16-18所示。

图16-18【例16_18】运行结果

从图16-18可以看出:只有奇数号的目标字符串被替换为*。

16.4.3设置Matcher搜索范围

Matcher的find()方法能够从整个字符串中进行搜索,如果希望对find()方法设置一个搜索范围,可以调用Matcher类的region()方法实现。region()方法的原型如下:

Matcher region(int start, int end)

region()方法的有两个参数,分别是start和end,它们表示要在下标为[start,end)的范围内进行搜索。需要注意:region()方法所设置的搜索范围仅能影响到find()方法,不会影响到replaceAll()方法的执行效果。下面的【例16_19】展示了region()方法的作用和效果。

【例16_19 设置搜索范围】

Exam16_19.java

import java.util.regex.*;
public class Exam16_19 {
    public static void main(String[] args) {
        String str = "0123456789";
        Pattern  p = Pattern.compile("\\d");//目标字符串是数字
        Matcher m = p.matcher(str);
        m.region(2,6);
        System.out.print("find()方法找到的所有目标字符:");
        while (m.find()){//持续搜索目标字符串
            System.out.print(m.group());//打印搜索到的目标字符串
        }
        System.out.println();//换行
        String replace = m.replaceAll("*");
        System.out.println("把str中所有数字替换为*:"+replace);
    }
}

【例16_19】的运行结果如图16-19所示。

图16-19【例16_19】运行结果

从图16-19可以看出:虽然设置了搜索范围,但并不影响replaceAll()方法把全部数字替换为“*”。

除阅读文章外,各位小伙伴还可以点击这里观看我在本站的视频课程学习Java!


 

<think>嗯,用户这周的Java作业是关于正则表达式的,有两个问题。首先得解释什么是正则表达式,然后写代码判断密码是否符合要求。让我仔细想想该怎么一步步解决。 第一个问题,什么是正则表达式?我记得正则表达式是用来匹配字符串模式的工具,可以验证输入是否符合特定格式,比如邮箱、电话号码之的。需要简单明了地解释,可能还要举例子,比如用\d表示数字,这样用户更容易理解。 第二个问题是代码作业,要求密码必须包含大写字母、小写字母、数字0-9,特殊字符,长度8位。这需要构造一个正则表达式,同时满足所有条件。正则的写法可能需要用到正向肯定预查,即(?=.*[条件]),每个条件都要检查,然后再加上长度限制。 首先,密码必须有大写字母,可以用(?=.*[A-Z]),同理小写字母是(?=.*[a-z]),数字是(?=.*\d),特殊字符的话可能需要定义哪些符号算特殊字符,比如[!@#$%^&*()_+]等。然后整体长度是8位,用.{8},但需要确保所有条件都满足。所以整个正则应该是多个正向预查加上最后的长度匹配。 不过,用户可能对特殊字符的范围不太清楚,可能需要给出常见的符号,并提醒注意转义字符,比如在Java字符串中反斜杠要写成两个。例如,正则里的特殊字符可能需要用\\来转义。 然后代码部分,用户需要用Java的Pattern和Matcher,或者String的matches方法。可能需要展示这两种方法,或者选一种简单的。比如用String.matches(regex),但要注意正则表达式是否正确。 可能用户会遇到的问题是,如何组合多个条件,确保每个条件都满足。正向预查应该可以处理这个问题,因为它们会检查每个位置是否存在对应的字符,而不管顺序如何。 另外,测试用例可能需要覆盖各种情况,比如缺少大写字母的情况,缺少小写字母,缺少数字,缺少特殊字符,或者长度不够的情况,来验证正则是否正确。 然后,用户可能需要一个完整的Java方法,接收密码字符串,返回是否符合要求。比如: public static boolean isValidPassword(String password) { String regex = "^(?=.*[A-Z])(?=.*[a-z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8}$"; return password.matches(regex); } 这里需要注意特殊字符的选择,比如是否包括@、$、!、%、*、?、&等,可能需要根据作业要求调整。如果题目没有明确说明,可能需要用户自己定义,或者使用更广泛的字符,比如[^A-Za-z0-9]来匹配非字母数字的字符。 不过使用[^A-Za-z0-9]可能会有问题,因为需要明确至少有一个特殊字符存在。这时候可以写成(?=.*[^A-Za-z0-9]),这样确保至少有一个非字母数字的字符。 所以调整后的正则可能是: ^(?=.*[A-Z])(?=.*[a-z])(?=.*\\d)(?=.*[^A-Za-z0-9]).{8}$ 这样更准确,因为[^A-Za-z0-9]会匹配任何非字母和数字的字符,即特殊字符。然后整个密码长度为8位,由任意字符组成,但必须满足前面的四个条件。 不过要注意,这样的正则可能会允许空格或其他不可见字符,但根据题目要求,可能不需要考虑这些,或者用户需要进一步明确特殊字符的范围。 因此,在代码中,可能需要根据题目具体要求调整特殊字符的部分。如果题目明确要求必须包含特定符号,就需要在正则中明确列出,如[@$!%*#?&]等。 总结步骤:解释正则表达式,然后构造满足所有条件的正则表达式,最后用Java代码实现验证方法。同时,给出示例代码和测试用例,帮助用户理解如何测试他们的程序。</think>### 分步解答 #### 1. 什么是正则表达式正则表达式(Regular Expression,简称Regex)是一种**字符串匹配模式**,用于: - **验证字符串格式**(如邮箱、电话号码) - **搜索/替换特定内容** - **提取字符串中的子信息** **核心语法**: - `\d` 匹配数字(等价于 `[0-9]`) - `[A-Z]` 匹配大写字母 - `[a-z]` 匹配小写字母 - `.` 匹配任意字符(除换行符) - `{n}` 匹配前一个元素恰好n次 - `^` 开头,`$` 结尾 - `(?=...)` 正向预查(确保存在某个模式,但不消耗字符) --- #### 2. 代码作业:密码验证 **需求分析**: - 必须包含:大写字母、小写字母、数字(0-9)、特殊字符 - 长度固定为8位 ##### 步骤1:构建正则表达式 **分解条件**: 1. **至少1个大写字母**:`(?=.*[A-Z])` 2. **至少1个小写字母**:`(?=.*[a-z])` 3. **至少1个数字**:`(?=.*\d)` 4. **至少1个特殊字符**:`(?=.*[!@#$%^&*()_+])`(可根据需求调整符号范围) 5. **总长度8位**:`.{8}` **组合后的正则表达式**: ```regex ^(?=.*[A-Z])(?=.*[a-z])(?=.*\d)(?=.*[!@#$%^&*()_+])[A-Za-z\d!@#$%^&*()_+]{8}$ ``` ##### 步骤2:Java代码实现 ```java import java.util.regex.Pattern; public class PasswordValidator { public static boolean isValidPassword(String password) { // 正则表达式定义 String regex = "^(?=.*[A-Z])(?=.*[a-z])(?=.*\\d)(?=.*[!@#$%^&*()_+])[A-Za-z\\d!@#$%^&*()_+]{8}$"; return Pattern.matches(regex, password); } public static void main(String[] args) { // 测试用例 System.out.println(isValidPassword("Abc123#")); // false(长度不足) System.out.println(isValidPassword("Abcdefg1")); // false(缺少特殊字符) System.out.println(isValidPassword("abc123#!")); // false(缺少大写字母) System.out.println(isValidPassword("AB123#!x")); // true(满足所有条件) } } ``` ##### 关键解释: - **正向预查** `(?=...)`:确保字符串中存在指定模式,但不占用匹配位置。 - **字符范围** `[!@#$%^&*()_+]`:定义允许的特殊字符,可根据实际需求增减。 - **转义字符**:Java中需用双反斜杠 `\\` 表示正则中的单个 `\`。 --- #### 常见问题 1. **特殊字符范围不明确**? - 修改正则中 `[!@#$%^&*()_+]` 部分,例如允许更多符号可扩展为 `[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>/?]`。 2. **密码长度超过8位**? - 将 `{8}` 改为 `{8,}` 允许更长密码,或 `{8,16}` 限制最大长度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

穆哥讲Java

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值