JavaSE学习笔记(20.Java之正则表达式)

1. 正则表达式介绍

最早正则表达式的产生是用于Unix的编辑器工具及grep工具,所以针对于正则表示规范可以通过The Single UNIX® Specification进行查询<Regular Expressions>

2. Java使用正则表达式

2.1 Pattern类和Matcher类:

java.util.regex包中提供了Pattern和Matcher两个类,用来实现通过正则表达式实现的字符串匹配、搜索、分割、替换等操作!

代码示例:

public class ReTest {
    public static void main(String[] args) {
        /*构造一个符合"\d{3}"含义的Pattern实例*/
        Pattern pattern = Pattern.compile("(\\d{3})(%)");
        /*通过Pattern类的split方法,进行字符串分隔*/
        String[] sa = pattern.split("a123%b456%c789%");
        Arrays.stream(sa).forEach(x -> System.out.println(x));

        /*通过Pattern类的matcher方法,构造一个需要与pattern正则表达式匹配的Matcher实例*/
        Matcher matcher= pattern.matcher("123%");
        /*通过Matcher类的matches方法,进行正则表达式匹配,符合返回true,不符合返回false*/
        System.out.println(matcher.matches());

        /*通过Matcher类的replaceAll方法,进行依照正则表达式的字符串替换*/
        Matcher matcher1 = pattern.matcher("hello 123%");
        System.out.println(matcher1.replaceAll("abc"));

        /*通过Matcher类的replaceAll方法,进行依照正则表达式的字符串替换*/
        Matcher matcher2 = pattern.matcher("hello 123%");
        System.out.println(matcher2.replaceFirst("abc"));

        /*通过Matcher类的group方法,进行依照正则表达式的字符串分组,0表示整个字符串,具体分组从1开始*/
        Matcher matcher3 = pattern.matcher("123%");
        matcher3.matches();
        System.out.println("group0 " + matcher3.group(0));
        System.out.println("group1 " + matcher3.group(1));
        System.out.println("group2 " + matcher3.group(2));

        /*通过Matcher类的find方法,进行依照正则表达式的字符串差找*/
        String s = "hello 123%";
        Matcher matcher4 = pattern.matcher(s);
        while(matcher4.find()) {
            String res = s.substring(matcher4.start(),matcher4.end());
            System.out.println(res);
        }
    }
}

输出:

Ps:

  • 调用Matcher类中的group方法,需要注意分组下标是从1开始的,group(0)表示字符串本身
  • Matcher类中的replaceAll和replaceFirst方法是通过find方法实现,但需要注意的是find方法的实现与matches方法实现不同;所以导致有些场景下,它俩并不等价;即matches匹配返回true的字符串并不一定是find的结果,例如下面的非贪心匹配;同时find方法可以找到字符串也不一定可以通过matches方法匹配返回true,例如下面的(?=表达式)等格式正则表达式!
  • 正则表达式后向引用,在调用replaceAll和replaceFrist方式时,可以使用$1、$2等参数来表示正则表达式的第一分组字符串和第二分组字符串

代码示例:

public class ReTest {
    public static void main(String[] args) {
        String s = "123%456a786&";
        Pattern pattern = Pattern.compile("(\\d{3})(.)");
        Matcher matcher = pattern.matcher(s);
        /*$2表示%,$1表示123;$2表示a,$1表示456;$2表示&,$1表示786*/
        System.out.println(matcher.replaceAll("$2$1"));
    }
}

输出:

2.2 String类中正则表达式的使用:

  • String类中的split方法、replaceAll和replaceFirst方法、matches方法都是依赖Pattern类和Matcher类实现的!
  • 在使用上述方法时,一定要特别注意正则表达式特殊字符的转义,否则可能会造成使用错误;比如说"abc|123|def".replaceAll("|","@"),则不能成功将字符串中的'|'字符替换成'@',因为'|'字符需要转义为'\\|'字符;但是String类中的replace()方法则没有问题,因为他是文本匹配而不是通过正则表达式匹配!

2.3 Java正则表达式的转义字符:

  •  由于Java中正则表达式也是一个字符串,同时Java本身在字符串描述的时候就需要使用'\'字符对部分特殊字符进行转义;所以Java中'\n'字符要被表示为正则表达式的时候需要表示为'\\n';第一个'\'用来说明在字符串转义的时候,对第二个'\'进行转义,第二个'\'用来在完成字符串转义后,用来对后面的n进行正则表达式的转义!所以如果在正则表达式中需要表示一个'\'字符,需要为'\\\\'!
  • 同样正则表达式中的特殊字符,如果需要仅仅表示字符本身含义而没有语法含义的时候,都需要加上转义字符'\';例如希望匹配?字符、*字符、.字符、-字符、|字符等等,字符的本意的时候,都需要加上转义字符"\\?",“\\*”等!

3. 正则表达式语法:

3.1 单字符匹配:

.字符:用来匹配除\n\t以为的一个任意字符

"a.b表示a+任意除\n\t意外的一个字符+b

\w字符:用来匹配任意一个字母、数字、下划线字符

"a\wb表示a+任意一个字母、数字、下划线+b

\d字符:用来匹配任意一个数字字符

"a\db表示a+任意一个字母、数字、下划线+b

\s字符:用来匹配\f\n\r\t\v中的任意一个字符

"a\sb"表示a+\f\n\r\t\v字符中的任意一个字符+b

3.2 重复匹配:

*字符:匹配零个或者多个*字符前面字符

"a*b*"表示n个a+n个b组成的字符串,n >= 0

+字符:匹配一个或者多个+字符前面字符

"a+b+"表示n个a+n个b组成的字符串,n > 0

?字符:匹配零个或者一个?字符前面字符

"a?b?"表示n个a+n个b组成的字符串,1 >= n >= 0

{}符号:匹配{}里描述数量的{}符号前面的字符

"a{3,5}b{4}c{1,}"表示n个a+m个b+k个c组成的字符串,5 >= n >= 3,m = 4,k >= 1

3.3 限定匹配:

[]符号:通过[]符号里面的范围匹配一个字符,可以枚举表示[012345]、范围表示[0-5];反向表示[^012345]、[^0-5]

"[012]"表示一个字符的范围为0、1、2;"[0-2]"为另一种表示形式

"[^012]"表示一个字符的范围不为0、1、2;"[^0-2]"为另一种表示形式

|字符:选择匹配一个通过|字符分割的字符串

"(AB|BA|ABA)"表示匹配"AB"、"BA"、"ABA"

3.4 占位匹配:

占位匹配的符号并不会真正参与字符的匹配,仅仅提供的是占位说明,主要用于正则表达式的搜索替换场景

\b字符:用来指示当前位置是一个单词边界位置,即字符串与空格之间的位置

"hello\s\ba\b"表示匹配"hello a",可见\b并不充当字符的匹配,仅仅起到一个位置说明的作用,用来说明当前位置为单词边界

^字符:用来指示一个字符串的开头

"^hello"表示匹配"hello"字符串并且"hello"在字符串开始位置,注意如果字符串为"hello1"则不能匹配

$字符:用来指示一个字符串的结尾

"hello$"表示匹配"hello"字符串并且"hello"在字符串结束位置,注意如果字符串为"1hello"则不能匹配

代码示例:

public class ReTest {
    public static void main(String[] args) {
        String s = "helloa";
        System.out.println(s.replaceAll("^hello","java"));
        String s1 = "ahello";
        System.out.println(s1.replaceAll("hello$","java"));
    }
}

输出:

3.5 反义匹配:

\W字符:匹配\w字符补集中的任意一个字符,即\w的反义匹配

\D字符:匹配\d字符补集中的任意一个字符,即\d的反义匹配

\S字符:匹配\s字符补集中的任意一个字符,即\s的反义匹配

\B字符:与\b同为占位匹配,指示当前位置不是一个单词边界位置,即\b的反义匹配

3.6 非贪心匹配:

*字符、?字符、+字符、{a,b}都存在贪心匹配的含义,即都匹配为一个范围;如果使他们都使用最小的匹配范围,就是非贪心匹配的概念!正则表达式中通过在上述符号后面增加?字符实现!

但是需要注意的是,非贪心匹配的实现仅仅对正则表达式分组、搜索、替换操作有效!对字符串正则表达式规则匹配,即matches方法无效!

代码示例:

public class ReTest {
    public static void main(String[] args) {
        /*非贪心匹配在正则表达式分组中的使用*/
        String s = "100000";
        Pattern pattern = Pattern.compile("(\\d{1,3}?)(0*)");
        Matcher matcher = pattern.matcher(s);
        System.out.println(matcher.matches());
        /*如果没有?符号,group(1)则输出100,group(2)则输出000*/
        /*根据范围限定第一组应该匹配最小范围1,所以输出1*/
        System.out.println(matcher.group(1));
        /*第二组,则应该输出00000*/
        System.out.println(matcher.group(2));

        /*非贪心匹配在正则表达式字符串替换中的使用*/
        String s1 = "100000";
        Pattern pattern1 = Pattern.compile("\\d{1,3}?");
        Matcher matcher1 = pattern1.matcher(s1);
        /*如果没有?符号,输出结果为"a000"*/
        /*当使用非贪心匹配规则后,输出结果为"a00000",说明匹配{1,3}的最小范围1*/
        System.out.println(matcher1.replaceFirst("a"));

        /*非贪心匹配在正则表达式字符串替换中的使用*/
        String s2 = "100";
        //String s2 = "10";
        //String s2 = "1";
        Pattern pattern2 = Pattern.compile("\\d{1,3}?");
        Matcher matcher2 = pattern2.matcher(s2);
        /*find方法并不一定与matches方法等价;在使用find方法进行字符串查找的时候,非贪心匹配的时候,只能找到最小的匹配规则
        * 但是在matches方法中,即使使用了?符号标记了非贪心匹配,依然可以匹配"1"、"10"、"100"等字符串,并没有严格进行非贪心匹配*/
        System.out.println(matcher2.matches());
    }
}

输出:

3.7 ?字符相关的几类表达式:

  • (?:表达式):正则表达式在通过()分组的时候,可以使用?符号,来标识当前分组不记录到group当中,此符号仅影响分组记录并不影响匹配规则!例如:(?:"ab")("cd")("ef")表达式,匹配规则依然是匹配"abcdef",但group(1)为"cd",group(2)为"ef",没有group(3)
  • XXX(?=表达式AAA):匹配后缀为表达式AAA的前缀字符串XXX,主要应用在字符串的查找和替换!虽然可以替换或者查找符合条件的XXX字符串,但是由于条件中必须要有AAA,所以不存在一个字符串可以满足该正则表达式使得matches方法返回true!
  • XXX(?!表达式AAA):为XXX(?=表达式AAA)的反匹配,匹配后缀不为表达式AAA的前缀字符串XXX
  • (?<=表达式AAA)XXX:匹配前缀为表达式AAA的后缀字符串XXX,原理与XXX(?=表达式AAA)一致,仅匹配顺序相反!
  • (?<!表达式AAA)XXX:为(?<=表达式AAA)XXX的反匹配,匹配前缀不为表达式AAA的后缀字符串XXX

代码示例:

public class ReTest {
    public static void main(String[] args) {

        /*示例:XXX(?=表达式AAA)*/
        String s1 = "Hello123";
        Pattern pattern1 = Pattern.compile("Hello(?=\\d{3})");
        Matcher matcher1 = pattern1.matcher(s1);
        System.out.println(matcher1.replaceAll("ok"));

        /*示例:XXX(?!表达式AAA)*/
        String s2 = "Hello12";
        Pattern pattern2 = Pattern.compile("Hello(?!\\d{3})");
        Matcher matcher2 = pattern2.matcher(s2);
        System.out.println(matcher2.replaceAll("ok"));

        /*示例:(?<=表达式AAA)XXX*/
        String s3 = "123Hello";
        Pattern pattern3 = Pattern.compile("(?<=\\d{3})Hello");
        Matcher matcher3 = pattern3.matcher(s3);
        System.out.println(matcher3.replaceAll("ok"));

        /*示例:(?<!表达式AAA)XXX*/
        String s4 = "12Hello";
        Pattern pattern4 = Pattern.compile("(?<!\\d{3})Hello");
        Matcher matcher4 = pattern4.matcher(s4);
        System.out.println(matcher4.replaceAll("ok"));

        /*不存在一个字符串满足上述正则表达式的matches匹配*/
        String s = "Hello";
        Pattern pattern = Pattern.compile("Hello(?=\\d{3})");
        Matcher matcher = pattern.matcher(s);
        System.out.println(matcher.matches());
    }
}

输出:

3.8 转义字符相关的匹配:

  • \f \r \n \t \v等转义字符:可以表示匹配一个非打印字符
  • \八进制:\字符后面+0+数字满足八进制要求即可表示匹配一个八进制的转义字符
  • \十六进制:\字符后面+x+满足十六进制要求的字符即可表示匹配一个十六进制的转义字符
  • \unicode码:\字符后面+u+满足unicode编码要求的字符既可以表示匹配一个unicode码的转义字符
  • \数字:\字符后面+数字(num > 0),表示针对前面通过分组匹配到的子串进行下标获取!看示例中详细说明!

代码示例:

public class ReTest {
    public static void main(String[] args) {
        String s = "ac11ac";
        /*该正则表达式中存在两个分组
        * 分组1为[a-d]{2},匹配字符为"ac"
        * 分组2为[1-3],匹配字符为"1"
        * 所以\1为"ac"子串的替换
        * \2为"1"子串的替换*/
        Pattern pattern = Pattern.compile("([a-d]{2})([1-3])\\2\\1");
        Matcher matcher = pattern.matcher(s);
        System.out.println(matcher.matches());
    }
}

3.9 运算符优先级:

运算符描述
\转义符
()、 (?:)、 (?=)、 []圆括号和方括号
*、+,、?、{n}、{n,}、{n,m}限定符
^、$、 \任意元字符、任意字符位置描述及占位
|或操作

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值