正则表达式--基础篇

本文是正则表达式系列文章的第二篇,基础部分,主要介绍重复匹配和位置匹配。

重复匹配

重复匹配用来匹配多个连续重复出现的字符或字符集合。

  • 指定匹配的重复次数{n,m}

    正则表达式可以通过{}元字符来定义重复范围,指定字符或字符集合重复多少次。

    • 指定具体的匹配次数{6}

      要想设置具体的匹配次数,把数字写在{}中间即可。

      示例: /#[A-Fa-f0-9]{6}/匹配一个HEX格式的color值,比如#FF0000

    • 指定范围区间{3,6}

      {}还可以用来为重复匹配次数设定一个区间范围,指定匹配的最小次数和最大次数。

      重复范围可以从0开始,比如{0,2}表示重复次数可以是0、1或2

      示例: /\d{3,6}/匹配一个最少3个数字,最多6个数字的字符串

    • 指定至少重复多少次{3,}

      类似于区间范围语法,只不过省略了最大值部分,比如{3,}表示至少重复3次(可重复3次或更多次)

      注意不能遗漏{3,}中的逗号,否则意义将从至少匹配3次变成只匹配3次。

      示例: /\$\d{3,}\.\d{2}/匹配大于等于$100的金额

  • 多少个匹配
    • 匹配一个或多个字符或字符集合+

      +用来匹配一个或多个字符(至少1个,不能为0个),等价于{1,}。

      示例: /[0-9]+/匹配一个或多个连续的数字。

    • 匹配零个或多个字符或字符集合*

      *用来匹配零个或多个字符(可有可无),等价于{0,}。

      示例: /[0-9]*/匹配零个或多个连续的数字。

    • 匹配零个或一个字符或字符集合?

      ?用来匹配零个或一个字符(出现0次或1次),等价于{0,1}。

      示例: /https?/匹配http或https协议。

  • 过度/贪婪匹配

    除了?、{3}、{3,6}这三种匹配形式外的其它重复匹配在重复次数方面都没有上限值,这就可能会出现过度匹配的现象。

    比如想要匹配<b>tree</b> and <b>grid</b>中的treegrid文本,将其变成大写格式。

    如果用/<b>.*</b>/匹配只会找到一个匹配结果tree</b> and <b>grid,而不是希望得到的两个。

    第一个<b>标签和最后一个</b>标签中的所有内容都被.*一网打尽。

    出现这个匹配结果的原因就是*是贪婪型的元字符。

    贪婪型元字符匹配行为是多多益善而不是适可而止,会尽可能地从一段文本的开头一直匹配到末尾,而不是碰到第一个就停止。

    如果不需要这种贪婪行为,可以通过在贪婪型量词后面加?的方式,将其变成懒惰型,以匹配尽可能少的字符。

    贪婪型量词 懒惰型量词
    * *?
    + +?
    {n,} {n,}?

    /<b>.*?</b>/就可以用来解决之前的问题了。

位置匹配

位置匹配用于指定应该在文本的什么地方进行匹配。

比如要匹配字符串The captain wore his cap and cape proudly as he sat listening to the recap中的cap单词,

如果用/cap/匹配,将会把captain,cap,cape,recap都匹配出来,这不是我们想要的结果。

这时就会用到边界,边界是一些用于指定模式前后位置/边界的特殊元字符。

这些元字符匹配到的只是位置,不匹配任何实际的字符

边界分单词边界和字符串边界。

  • 单词边界\b\B

    用来对单词位置进行匹配,匹配单词的开头、结尾、整个单词等。

    • 匹配一个单词的开头或结尾\b

      正则表达式不懂英语在内的任何人类语言,\b匹配的是字符之间的一个位置: 一边是单词(能被\w匹配到的字符),另一边是其他内容(能被\W匹配到的字符)。

      它不匹配任何实际的字符,比如用/\bui\b/匹配到的字符串长度是2个字符(u,i),而不是4个字符。

      示例1: /\bcap\b/匹配单词cap,而不会匹配到captain,cape,recap

      示例2: /\bcap/匹配以cap开头的单词captain,cap,cape,而不会匹配到recap

      示例3: /cap\b/匹配以cap结尾的单词cap recap,而不会匹配到captain,cape

    • 匹配非单词边界\B

      示例1: 添加千位分隔符,

                                      
                                          "12345678.90".replace(/\B(?=(?:\d{3})+(?!\d))/g,",");
                                          //结果为"12,345,678.90"
                                      
                                  

      示例2: /\B-\B/匹配前后都不是单词边界的-连字符,将会匹配到"a-b,c - d"中第2个-,而不会匹配到第1个-

  • 字符串边界^$

    匹配字符出现在字符串中的位置,字符串开头和结尾。

    一般用在表单中做校验的正则表达式都会添加字符串边界。

    • 匹配字符串开头^

      注意^只有出现在[]里,并且紧跟左侧[后面时,它才会表示排除该字符集合,如果出现在[]之外并位于模式的开头,^将匹配字符串的起始位置

      示例: /^\s*<\?xml.*?\?>/匹配一段文本是否是xml格式,^\s*匹配字符串的开头和随后的若干个空白字符。

    • 匹配字符串结尾$

      用法和^类似

      示例: /</html>\s*$/可以用来检查web页面结尾的</html>后是否有除空白字符以外的其他内容。

    有些正则表达式实现还支持\A,\Z来标记字符串的开头和结尾