[疯狂Java]正则表达式:Java正则表达式语法、贪婪模式/勉强模式

1. 基本字符和特殊字符:

    1) 正则表达式前面讲过了,是需要先编译再执行的,因此从某种方面来将正则表达式其实也是一种特殊的编程语言;

    2) 既然是编程语言(特殊的编程与语言)那么它就有它自己的源代码字符、关键字等概念了;

    3) 正则表达式没有像其它编程语言一样的关键字(像if、else、while等),它的关键字是特殊字符,因此正则表达式的源码分为基本字符和特殊字符:

    4) 基本字符:包括所有的英文字母(大小写都包含)和数字(0-9),它们就是纯文本字符,它们只代表自己本身;

    5) 特殊字符:基本上都是一些符号字符,例如*、\、^等,它们不是纯文本字符,有特殊含义,正则表达式引擎会把它们解释成命令并编译成子函数;

    6) 这里先介绍两个最重要的特殊字符,它们在后面会有大量应用:

         i. \:转义字符,用于转义紧跟在它后面的下一个字符,使其具有特殊含义;

         ii. ():标记子表达式的开始和结束,即用()括起来的部分就是一个子表达式;


2. 匹配单个字符:

    1) 基本字符(普通字符):所有的英文字母(包括大小写)和纯数字(0-9),之前已经讲过了;

    2) 用ASCII编码来表示字符:有两种形式,一种是8进制形式,一种是16进制形式

         i. \0XX:X表示八进制数(0-7);

         ii. \xXX:X表示十六进制数(0-9、a-f,不分大小写,,一般推荐大写,大写更美观);

!!由于这两种形式只能表示ASCII编码,而ASCII编码范围是十进制的[0, 127],因此八进制表示法的X最多有2个,而十六进制的X最多也只有两个!!

    3) 用Unicode编码来表示字符:\uXXXX

!!X表示十六进制数(字母不区分大小写),必须是4个X,不能缺省(ASCII码表示法可以缺省);

    4) 控制符:

         i. \t:制表

         ii. \n:换行

         iii. \r:回车

         iv. \a:报警

         v. \e:Escape

         vi. \cX:Ctrl+X,例如\cM就表示Ctrl+M,其中X是英文字母(包括大小写)


3. 中括号表达式:范围匹配,一种特殊的匹配单个字符的方法

    1) 即[ ]表达式,用来匹配单个字符,只不过这一个字符的所在范围有中括号内的表达式来确定

    2) 枚举:[abc],表示匹配a、b、c的任意一个

    3) 范围:[a-f],表示匹配a-f之间的任意一个字符,包括边界,其中右边界一定要≥左边界,否则引擎编译错误

    4) 并:[a-cm-p],就表示a-c的范围和m-p的范围求并,其实前面的abc之类的枚举也是一种并运算

    5) 交:[a-z&&b-d],就表示a-z的范围和b-d的范围求交,结果等于[b-d]

    6) 补:[^abc]表示非a、b、c的任意一个字符,[^a-f]表示非a-f的任一字符;^也是一个脱字符,必须是中括号表达式的第一个字符,否则不起任何作用!!

!补的是^后面紧跟的整个表达式!

    7) 嵌套:[a-m&&[def]],a-m和[def]都表示范围,因此可以做运算,结果等于[d-f]

    8) 有了上面这些基本运算,就可以构造一些很复杂的运算了:[a-z&&[^bc]] == [ad-z]

!!但是注意不要用^构造复杂表达式,以下一些表达式将不起作用!

        a. ^后面紧跟一个[ ]嵌套:^[a-d],非法!不起任何作用

        b. ^后面是一个运算(交并补):^a-cf-h、^a-z&&c-h、^^a-c,都是非法的!!不起任何作用!!

        c. ^后面只能跟单纯的枚举和范围运算!!例如[^azh]、[^a-h]等;



4. 前面紧邻的子表达式的重复次数:

    1) *:重复0次或多次

    2) +:重复1次或多次

!!常用:\w+表示匹配一个单词!

    3) ?:重复0次或1次

    4) {n}:刚好重复n次

        {n,}:重复≥n次,即≥n次的都可以

        {n,m}:重复[n, m]次,即n≤  ≤m的都可以

!!不能有任何多余的空格,否则直接编译(引擎编译)不通过;

!!n必须为非负整数,且n≤m,否则也会引擎编译不通过;


!!贪婪模式和勉强模式:解决重复次数匹配的歧义(就是上面的重复次数匹配)

        a. 由于重复次数的匹配可能匹配到多种结果,例如:x{2, 3}匹配xxxx,既可以匹配xx,也可以匹配xxx,因此存在歧义;

        b. 但是任何编程语言,包括正则表达式,都是不允许有任何歧义的,因此底层必定有避免歧义的机制;

        c. 正则表达式引擎默认使用贪婪模式解决歧义问题,贪婪模式:只要符合要求就一直匹配下去,直到无法匹配为止,即上面的结果就是2和3都存在,就往大的取!只取上限,包括*、+、?都是一样的,例如ab.*zz匹配abcxxzzsfewzzq的结果是abcxxzzsfewzz,并没有在abcxxzz处停止,而是直到最后的zzq不能再匹配时才停止匹配!

        d. 与贪婪模式对应的就是勉强模式:只匹配下限,即只往少的匹配,一找到符合要求的就立马匹配成功,不再管后面的序列,在勉强模式下*匹配0个,+匹配一个,?匹配0个,而{ }只匹配下限!

        f. Java是支持勉强模式的,勉强模式的表示方式是重复次数字符后面紧跟一个?,例如??就表示勉强模式的?,+?就表示勉强模式的+,*?就表示勉强模式的*,{ }?就表示勉强模式的{ };


5. 通配符:

    1) .:匹配\r和\n之外的任意其他字符

    2) \d:匹配任意一个数字(0-9),即digit

    3) \D:匹配任意一个非数字

    4) \s:匹配任意一个空白符(制表、换行、空格、换页、回车等),即space

    5) \S:匹配任意一个非空白符

    6) \w:匹配任意一个单词字符,单词字符指0-9、26个英文字母(包括大小写)、下划线(_),注意是一个字符!而不是一个单词

    7) \W:匹配任意一个非单词字符


6. 匹配起始和结尾:锚

    1) ^:脱字符,匹配主串的开头,即必须以^后面紧跟的子表达式为开头,例如^abc可以匹配abcxxx,group的返回结果是abc

    2) $:锚字符,匹配主串的结尾,即必须以$前面紧跟的子表达式结尾,例如abc$可以匹配qqqxxabc,group的返回结果是abc

    3) 组合锚点:例如,^book.*end$可以匹配所有以book起始以end结尾的子串

    4) 脱字符必须作为模式串的起始,锚字符必须作为$模式串的结束,否则将不会起到任何作用!!

!例如,abc^xq并不能匹配abcxquuu,而abc$zx并不能匹配abczxddd!!


7. 匹配单词边界:boundary

    1) \b:前面紧邻的子表达式必须是单词的边界(单词之间用空白符分隔),例如:ok\b可以匹配"book lala"中的book的ok,但不能匹配"books lala",group返回的也是ok

    2) \B:前面紧邻的子表达式必须“不是”单词的边界,例如:ok\B可以匹配"books lala"中的books的ok,但不能匹配"book lala",group返回的也是ok


8. 或运算:|

    1) 表示指定两项(表达式)之间任选一项,即或运算;

    2) 例如a|b等于[ab],(public)|(private)就表示这两个单词任意匹配一个,但最好不要写成public|private,这可能表示匹配publicrivate或者publiprivate,有些引擎就会判定歧义;

!!良好的习惯:自己不确定是否产生歧义的时候就加一下()变成子表达式,一目了然,而且可以避免错误!!


9. 所有特殊字符的纯文本形式都必须转义!

    1) 像.、^、$、\、|、[、]、{、}、(、)等特殊字符,如果想表示其纯文本形式,都必须使用\转义;

    2) 例如\(就表示纯文本的'('字符;


10. 在Java源代码中编写正则表达式:

    1) 由于正则表达式使用的是自己的字符,而Java源代码也有自己的字符,这就会导致两者之间发生一些不可避免的冲突;

    2) 最大的冲突就是\,正则表达式中\就是一个字符(特殊字符),而Java中要表示纯文本的\也需要转义,即用\\来表示纯文本的\;

    3) 而Java源代码中编写的正则表达式对于Java源代码来说应该是纯文本,这就意味着,Java源代码中编写的正则表达式中的\都必须要用\\来表示;

    4) 例如:正则表达式\w在Java源码中编写就必须写成\\w,比较麻烦

!小结:所有在Java源码中编写的正则表达式中的\都必须用\\表示,如果你觉得上面的原理看着头晕,那就记住这句简单的小结即可,无脑使用;

!!即先正常写好正则表达式,然后把里面所有的\换成\\即可;

    5) 一般为了避免这种麻烦的事情,都是先在程序外部的配置文件中写好正则表达式,然后在程序中读取、编译并使用,这就避免了两者字符集的冲突了;



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值