一.正则表达式元字符

1.转义元字符

\ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个向后引用、或一个八进制转义符

1.如果我们想匹配一些特殊符号本身,比如 . * + ( ) $ / \ ? [ ] ^ { } | 我们需要使用转义符\

如果不转义,它将有特殊含义,因此使用转义符\可以将它们的意义变为本身

2.d代表字母d,但是\d就代表0-9的一个数字了,这也是转义符的作用,将某个符号改变它原来的意思,这样的类型也不是很多,而且好记,下面会讲到

注意:Java语言环境中两个\\才代表一个\

在这里插入图片描述

在这里插入图片描述

2.特殊元字符

[ ]代表匹配的为可选项,即该括号里面的不一定全匹配,无顺序的概念,该括号里面代表的仅仅是可选择的符号列表

()标记一个子表达式的开始和结束位置,该括号里面要全部匹配才可以,并且有顺序概念。子表达式可以获取供以后使用

例如,[adc]可匹配a、d、c、ad、ac、adc、dc、ca等(但ca这种的实际是c单独匹配,a单独匹配)

在这里插入图片描述

但(abc)只能匹配abc

在这里插入图片描述

[] 可接受的字符列表

[adc] 可匹配a、d、c、ad、ac、adc等
在这里插入图片描述
表示可匹配 a | c这三个符号
在这里插入图片描述
但是 | 在()里代表 或者的意思,特例

在这里插入图片描述

[^] 不可接受的字符列表
在这里插入图片描述
( ) 标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用

在这里插入图片描述

- 连字符

例如a-z代表小写的26个字母,A-Z代表26个大写字母,0-9代表10个数字
在这里插入图片描述

\d 匹配任意一个数字
在这里插入图片描述

\D 匹配一个任意非数字字符
在这里插入图片描述

\w 匹配一个数字或者字母(大小写均可)或者 _
在这里插入图片描述

\W 匹配一个非数字非字母(包括大小写)非 _ 的字符
在这里插入图片描述

. 匹配一个除\n以外的任意字符
在这里插入图片描述

| 指明两项之间的一个选择。要匹配 |,请使用 \|

在这里插入图片描述

3.限定元字符

这里子表达式可以是单个字符,也可以是[]括号括起来的,也可以是()括起来的,两种还是有区别的,例如(abc){3}代表abc要出现3次才匹配,而[abc]{3}代表前面的abc任意出现三次即可

{n} n 是一个非负整数。匹配前面子表达式确定的 n 次

以ab开头,且必须跟3个c才可以
在这里插入图片描述
{n,} n 是一个非负整数。至少匹配前面子表达式n 次

在这里插入图片描述

{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次

在这里插入图片描述

* 匹配前面的子表达式零次或多次

在这里插入图片描述
在这里插入图片描述

+ 匹配前面的子表达式一次或多次

在这里插入图片描述

? 匹配前面的子表达式零次或一次

在这里插入图片描述

非贪婪

当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串

示例1

abc 是匹配ab开头,c可以0次或者多次,如图*
在这里插入图片描述
但是加一个?,变成非贪婪,让*取最小值,0次
在这里插入图片描述
示例2

abc+匹配ab开头,c可以1次或者多次
在这里插入图片描述
但是加一个?,让+取最小值,也就是1次
在这里插入图片描述

4.定位元字符

\b 匹配一个单词边界,也就是指单词和空格间的位置

在这里插入图片描述
\B 匹配非单词边界 (非空格才可以)

在这里插入图片描述
^ 在[]外用,代表必须开始的位置

^abc必须以abc开始
在这里插入图片描述
在这里插入图片描述
$ 代表结束的位置

$abc必须以abc结尾
在这里插入图片描述

^abc$ 必须是abc,不能包含任何的其他
在这里插入图片描述

5.非打印元字符

\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]

\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]

\f 匹配一个换页符。等价于 \x0c 和 \cL

\n 匹配一个换行符。等价于 \x0a 和 \cJ

\r 匹配一个回车符。等价于 \x0d 和 \cM

6.修饰符

正则表达式 - 修饰符(标记)
标记也称为修饰符,正则表达式的标记用于指定额外的匹配策略

标记不写在正则表达式里,标记位于表达式之外,格式如下:

/pattern/flags

i ignore - 不区分大小写 将匹配设置为不区分大小写,搜索时不区分大小写: A 和 a 没有区别

g global - 全局匹配 查找所有的匹配项

m multi line - 多行匹配 使边界字符 ^ 和 $ 匹配每一行的开头和结尾,记住是多行,而不是整个字符串的开头和结尾

在这里插入图片描述
在这里插入图片描述

s 特殊字符圆点 . 中包含换行符 \n 默认情况下的圆点 . 是匹配除换行符 \n 之外的任何字符,加上 s 修饰符之后, . 中包含换行符 \n

二.正则表达式基础

1.捕获分组

非命名分组

用圆括号 () 将所有选择项括起来,相邻的选择项之间用 | 分隔

() 表示捕获分组,() 会把每个分组里的匹配的值保存起来, 多个匹配值可以通过数字 n 来查看(n 是一个数字,表示第 n 个捕获组的内容)

捕获的含义就是我们保留了分组内容,可以通过分组序号引用

(\d\d)(\d\d)表示匹配4个连续的数字,并且第一个数字和第二个是第一组,第三四是第二组!组号从1开始
在这里插入图片描述

public class Regex01 {
    public static void main(String[] args) {
        String content = "ABCab123@45";
        String regStr = "(ab|cd)(12|34)";

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);

        while (matcher.find()){
            System.out.println(matcher.group(1));
            System.out.println(matcher.group(2));
        }

    }
}

在这里插入图片描述

命名分组

public class Regex01 {
    public static void main(String[] args) {
        String content = "ABCab123@cd34";
        String regStr = "(?<g1>ab|cd)(?<g2>12|34)";

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);

        while (matcher.find()){
            System.out.println(matcher.group("g1"));
            System.out.println(matcher.group("g2"));
        }

    }
}

在这里插入图片描述

2.非捕获分组

?= ?<= ?! ?<! ?:主要涉及这五种

直接看例子

exp1 (?:exp2) 查找exp1连接exp2的匹配

在这里插入图片描述

exp1(?=exp2):查找 exp2 前面的 exp1

查找!前面的juman
在这里插入图片描述
在这里插入图片描述
(?<!exp2)exp1:查找前面不是 exp2 的 exp1

在这里插入图片描述
(?<=exp2)exp1:查找 exp2 后面的 exp1

在这里插入图片描述
在这里插入图片描述

exp1(?!exp2):查找后面不是 exp2 的 exp1

在这里插入图片描述

3.反向引用

()捕获分组后,可以在这个括号后面使用,如果在正则表达式内部,那么用\分组号
引用,如果在正则表达式外部,用$分组号引用

这里的反向其实也没有实际意义,其实就是引用分组的概念

(\d\d)\1\1代表我首先匹配两个数字,并且后面的4个数字要和我相同,也即匹配3组连续相同的数字,\1代表引用分组1
在这里插入图片描述

在这里插入图片描述

public class EncryptPhoneNumber extends UDF implements Serializable {
    /**
     * 重载evaluate方法 实现函数的业务逻辑
     * @param phoNum  入参:未加密手机号
     * @return 返回:加密后的手机号字符串
     */
    public String evaluate(String phoNum){
        String encryptPhoNum = null;
        //手机号不为空 并且为11位
        if (StringUtils.isNotEmpty(phoNum) && phoNum.trim().length() == 11 ) {
            //判断数据是否满足中国大陆手机号码规范
            String regex = "^1[3-9]\\d{9}$";
            Pattern p = Pattern.compile(regex);
            Matcher m = p.matcher(phoNum);
            if (m.matches()) {//进入这里都是符合手机号规则的
                //使用正则替换 返回加密后数据
                encryptPhoNum = phoNum.trim().replaceAll("(\\d{3})\\d{4}(\\d{4})","$1****$2");
            }else{
                //不符合手机号规则 数据直接原封不动返回
                encryptPhoNum = phoNum;
            }
        }else{
            //不符合11位 数据直接原封不动返回
            encryptPhoNum = phoNum;
        }
        return encryptPhoNum;
    }
}

三.Java使用正则表达式

1.基本使用

用Pattern.compile(regStr);来确定正则表达式

用pattern.matcher(content);来匹配内容

public class Regex01 {
    public static void main(String[] args) {
        String content = "ABCab123@cd34";
        String regStr = "(ab|cd)(12|34)";

        Pattern pattern = Pattern.compile(regStr);
        Matcher matcher = pattern.matcher(content);

        while (matcher.find()){
            System.out.println(matcher.group(0));
            System.out.println(matcher.group(1));
            System.out.println(matcher.group(2));
        }

    }
}

**matcher.find()**代表找到了符合匹配的东西

接下来是重点,我们debug一下

发现group数组是一个初始值为-1,大小为20的数组!
在这里插入图片描述
当我们找到了第一个符合要求的匹配时,数组变了,变了前6位
在这里插入图片描述
变的是什么呢?我们找到的第一个匹配结果是ab12,这四个字符对应的开始索引是3,结束索引是6,我们于是明白了,group第一位(下标为0)是找到的匹配结果的开始索引第二位是结束索引+1,于是不难看出,第三位是第一组开始的索引,第四位是第一组结束的索引+1,第五位是第二组开始的索引,第六位是第二组结束的索引+1
在这里插入图片描述
当我们运行到第二个结果cd34的时候,发现这个数组竟然发生了覆盖!!
在这里插入图片描述

也就是说group数组只会匹配一个符合条件的结果,前两位索引正是这个结果的开始和结束索引+1,后面的就是具体到每个组了!!

2.String类结合正则

替换

s.replaceAll

public class Regex01 {
    public static void main(String[] args) {
        String s = "12345678910";
        String s1 = s.trim().replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
        System.out.println(s1);
    }
}

在这里插入图片描述

判断

s.matches

public class Regex02 {
    public static void main(String[] args) {
        String s = "12345678910";
        boolean b = s.matches("^123\\d{8}");
        System.out.println(b);
    }
}

在这里插入图片描述

分割

s.split

数字字符分割

public class Regex03 {
    public static void main(String[] args) {
        String s = "12345-678!gh-910";
        String[] split = s.split("\\-|\\!");
        for (String s1 : split) {
            System.out.println(s1);
        }
    }
}

在这里插入图片描述

更多推荐