正则表达式

本文深入探讨了正则表达式的原理与应用,包括局部匹配和整体匹配,详细解析了元字符、限定符、分组等核心概念。通过实例展示了如何使用正则表达式进行字符串匹配,并解释了非贪婪匹配和选择匹配符的用法。此外,还介绍了正则表达式在Java中的具体实现,如Pattern和Matcher类的使用。
摘要由CSDN通过智能技术生成

正则表达式

正则表达式是对字符串执行模式匹配的技术

底层实现分析

局部匹配

public class RegexpDemo01 {
    public static void main(String[] args) {
         String str = "在1958 年,一位名叫Stephen Kleene的数学科学家博尔特," +
                 "1963,他在Warren McCulloch和Walter Pitts早期工作的基础之上,发表了一篇题目是" +
                 "《神经网事件的表示法》的论文,1969利用称之为正则集合的数学符号来描述此模型,引入" +
                 "了正则表达式的概念。1971正则表达式被作为用来描述其称之为“正则集的代数”的一种表达式," +
                 "因而采用了“正则表达式”这个术语。";

         // 匹配正则表达式字符 匹配四个数字
         String regexp = "\\d\\d\\d\\d";
         // 生成模式对象
         Pattern pattern = Pattern.compile(regexp);
         // 匹配字符
         Matcher matcher = pattern.matcher(str);
        
        /*
         * matcher.find()
         * 1. 根据 pattern 的规则, 定位满足规则的字符串(比如:1958) 在str的开始索引位置(1)和结束索引位置+1(5)
         * 2. 将索引位置记录到数组groups; 的下标 groups[0] = 0 groups[1] = 4
         * 3. 并且下一次索引开始等于当前的结束索引位置+1 (设置为 5, 表示下一次匹配从5开始)
         * 4. 下次找到数字1963 始索引位置(36)和结束索引位置+1(40)
         * 5. 将索引位置记录到数组groups;的下标groups[0] = 0 groups[1] = 4 记住会覆盖之前的数组下标0,1的数组
         *
         *     特别说明: 当在正则表达式中有()(如(\\d\\d)(\\d\\d) ),则表示分组
         *     第1个() 表示第一组  第2个() 表示第2组
         *     2.1 groups[0] groups[1] 记录匹配到的完整结果 如: 1958
         *     2.2 groups[2] groups[3] 记录匹配到的结果的第一个()的内容的开始索引和结束索引+1 即0和2
         *     2.3 groups[4] groups[5] 记录匹配到的结果的第2个()的内容的开始索引和结束索引+1 即2和4
         *
         * ----------------------------------------------------------------------------------------
         *
         * matcher.group(index)
         *     源码分析
         *     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. 如果matcher.group(1)从字符串截取下标 groups[0] 到 groups[1]-1 的子字符串
         * 2. 如果matcher.group(1) 截取 groups[2] 到 groups[3] 对应索引的子字符串
         * 2. 如果matcher.group(2) 截取 groups[4] 到 groups[5] 对应索引的子字符串
         *
         * 然后循环的执行find和group的方法
         */
         while(matcher.find()){ // 如果查找数组找到的值为-1即没有存入数据则返回false
             System.out.print(matcher.group(0) + "  "); // 1958  1963  1969  1971
         }
    }
}

整体匹配

public static void main(String[] args) {
    String str = "12345";
    // 匹配正则表达式字符 匹配四个数字
    String regexp = "\\d\\d\\d\\d";
    // 匹配字符 完成匹配
    boolean isMatch = Pattern.matches(pattern,content);
    System.out.println(isMarch); // false
}

正则表达式语法

元字符
转义符
// 转义符:\\ 
public static void main(String[] args) {
    String str = "在1958 年,一位名叫Stephen Kle(ene的(数学科学家博尔特(";
    String regexp = "\\("; // ( 会报错
    Pattern pattern = Pattern.compile(regexp);
    Matcher matcher = pattern.matcher(str);
    while (matcher.find()){
        System.out.println(matcher.group(0)); // 3个 (
    }
}
限定符

用于指定其前面的字符和组合项连续出现多少次

符号含义示例说明匹配输入
*指定字符重复0次或n次(无要求)零到多(abc)*仅包含任意个abc的字符串,等效于\w*abc,abcabcabc
+指定字符重复1次或n次(至少一次)m+(abc)*以至少1个m开头,后接任意个abc的字符串m,mabc,mabcabc
指定字符重复0次或1次(最多一次)m+abc?以至少1个m开头,后接ab或abc的字符串mab,mabc,mmmab
{n}只能输入n个字符[abcd]{3}由abcd中字母组成的任意长度为3的字符串abc,dbc,adc
{n,}指定至少n个匹配[abcd]{3,}由abcd中字母组成的任意长度不小于3的字符串aab,dbc,aaabdc
{n,m}指定至少n个但不多于m个匹配[abcd]{3,5}由abcd中字母组成的任意长度不小于3,不大于5的字符串abc,abcd,aaaaaa,bcdab
?匹配模式是"非贪心的"。"非贪心的"模式匹配搜索到的、尽可能短的字符串当此字符紧随任何其他限定符(*、+、?、{n}、{n,}、{n,m})之后时,

注意:java匹配默认贪婪匹配,即尽可能匹配多的数量 如 a{3,4} : aaaa优先级 > aaa优先级

选择匹配符

在选择匹配某个字符串的时候是选择性的( | )

符号含义示例解释
|匹配“|”之前或之后的表达式ab|bcab或者bc
分组组合

常用分组

常用分组构造形式说明
(pattern)非命名捕获。捕获匹配的子字符串。编号为零的第一个捕获是由整个正则表达式模式匹配的文本,其它捕获结果则根据左括号的顺序从1开始自动编号
(?< name >pattern)命名捕获。将匹配的子字符串捕获到一个组名称或编号名称中。用于name的字符串不能包含任何标点符号,并且不能以数字开头。可以使用单引号替代尖括号,例如(?‘name’)
public static void main(String[] args) {
    String str = "在1958 年,一位名叫Stephen Kleene的数学科学家博尔特," +
        "1963,他在Warren McCulloch和Walter Pitts早期工作的基础之上,发表了一篇题目是" +
        "《神经网事件的表示法》的论文,1969利用称之为正则集合的数学符号来描述此模型,引入" +
        "了正则表达式的概念。1971正则表达式被作为用来描述其称之为“正则集的代数”的一种表达式," +
        "因而采用了“正则表达式”这个术语。";

    // 匹配正则表达式字符 匹配四个数字
    // 非命名分组
    String regexp = "(\\d\\d)(\\d\\d)";
    // 生成模式对象
    Pattern pattern = Pattern.compile(regexp);
    // 匹配字符
    Matcher matcher = pattern.matcher(str);
    while(matcher.find()){
        //  1958  19  58
        //  1963  19  63
        //  1969  19  69
        //  1971  19  71
        System.out.print(matcher.group(0) + "  ");
        System.out.print(matcher.group(1) + "  ");
        System.out.print(matcher.group(2) + "  ");
        System.out.println();
    }

    System.out.println("=====================");

    // 命名分组
    regexp = "(?<group1>\\d\\d)(?<group2>\\d\\d)";
    pattern = Pattern.compile(regexp);
    // 匹配字符
    matcher = pattern.matcher(str);
    while(matcher.find()){
        //  1958  19  58
        //  1963  19  63
        //  1969  19  69
        //  1971  19  71
        System.out.print(matcher.group(0) + "  ");
        System.out.print(matcher.group("group1") + "  ");
        System.out.print(matcher.group("group2") + "  ");
        System.out.println();
    }
}

特别分组

常用分组构造形式说明
(?:pattern)匹配pattern但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用"o"字符()组合模式部件的情况很有用。例如,'industr(?yies)是比’industryindustries’更经济的表达式
(?=pattern)它是一个非捕获匹配。例如,Windows(?=9598NT2000)'匹配"Windows2000"中的"Vindows",但不匹配"Vindows3.1"中的"Windows"
(?!pattern)该表达式匹配不处于匹配pattern的字符串的起始点的搜索字符串。它是一个非捕获匹配。例如,“Nindows(?!9598NT2000)'匹配"Windows3.1"中的"Windows”,但不匹配"Windows2000"中的"Vindows"
// (?:pattern)
String str = "罗念笙同学和罗念笙父亲以及罗念笙母亲要一起出席会场";
String regexp = "罗念笙(?:同学|父亲|母亲)"; // 等价于 "罗念笙同学 | 罗念笙父亲 | 罗念笙母亲)"
Pattern pattern = Pattern.compile(regexp);
Matcher matcher = pattern.matcher(str);
while(matcher.fins()){
    // 不能使用group(1)捕获分组,但是整体是可以用group(0)捕获
}

// (?=pattern) 和 (?!pattern) 取反关系
字符匹配符
符号含义示例解释
[ ]可接受的字符列表[efgh]e,f,g,h中的任意一个字符
[^]不接收的字符列表[^abc]a,b,c之外的任意一个字符,包括数字和特殊字符
-连字符A-Z任意一个大写字母
.匹配除\n以外的任何字符a…b以a开头,b结尾,中间包括2个任意字符的长度为4的字符串
\ \d匹配单个数字字符,相当于[0-9]\ \d{3}(\ \d)?包含3个或4个数字的字符串
\ \D匹配单个非数字字符,相当于[ ^ 0-9]]\ \D(\ \d)*以单个非数字字符开头,后接任意个数字字符串
\ \w匹配单个数字、大小写字母字符相当于[0-9a-zA-Z]\ \d{3}\ \w{4}以3个数字字符开头的长度为7的数字字母字符串
\ \W匹配单个非数字、大小写字母字符相当于[ ^ 0-9a-zA-Z]\ \W+\ \d{2}以至少1个非数字字母字符开头,2个数字字符结尾的字符串
\ \ s匹配任何空白字符(空格,制表符等)空格,制表符
\ \ S匹配任何非空白字符除空格,制表符之外
// 细节说明
// 不区分大小写
(?!)abc  //  abc都不区分大小写
a(?!)bc  //  abc都不区分大小写
a((?!)b)c // 只有b不区分大小写
Pattern pattern = Pattern.compile(regexp,Pattern.CASE_INSENSITIVE);
定位符

规定要匹配的字符出现的位置

符号含义示例说明匹配输入
^指定起始字符^ [0-9] + [a- z]*以至少1个数字开头,后 串123, 6aa
$指定结束字符^ [0-9]\ \ - [a-z] + $以1个数字开头后接连字符“-”,并以至少1个小写字母结尾的字符串1-a
\ \ b匹配目标字符串的边界lns\ \ b这里说的字符串的边界指的是子串间有空格,或者是目标字符串的结束位置splns,hallns
\ \ B匹配目标字符串的非边界lns \ \ B和b的含义刚刚相反lnssp,lnsfh
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

罗念笙

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

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

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

打赏作者

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

抵扣说明:

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

余额充值