初识正则表达式

其实一开始让我学正则我是拒绝的,因为你不能让我去学我就去学,我得先试一试,要是太难了我就不学了。然后一看,这一串中括号大括号是什么鬼,果断不学。后面打算搞一点爬虫的时候,才发现正则式绕不过去的槛,加上最近的项目,需要在页面先进行一遍表单验证巴拉巴拉之类的,然后才重拾正则的学习笔记,进行一番捣鼓。下面是正则基础篇,凑合着能应付普通的要求了。(会写正则的人都很酷的样子,哈哈!)

<!--more-->

学习的时候参照的两篇文章:轻松学习正则表达式(强烈推荐!!!)和55分钟学会正则表达式。 学习正则,最主要的知识点就是三类符号:括号(包括(),[],{}),起始符号(^)和结束符号($)。

1. 起始符与终止符

起始符和结束符的意义十分明确:起始符表示规定查找的字符串以“^”后跟的字符(或字符串——需要分组)开始;结束符表示规定查找的字符串以“$”前接的字符(串)结束,就是这么简单,比如表示以a开头,以b结尾的单词:

    var re = /^a.b$/;//“.”字符可以理解为类似于C语言的占位符,表示可以匹配任意字符
    var s = "axb";
    console.log(re.test(s));//true

当然,这两个符号并不是一个正则表达式所必须的,可以根据需要灵活使用。

    var re = /a.b/;
    var s = "Halbo";
    console.log(s.match(re));//alb

2. 括号符号

2.1. 中括号

“[]”内包含的是需要匹配的字符集合,可以只有一个字符,也可以是多个字符的集合(包括数字字母各种有意义的转义字符等等)。比如:

  • 可以是[0-9](表示匹配一个数字),可以简写成[\d];
  • 可以是[a-zA-Z0-9_](表示匹配一个常规字符),可以简写成[\w];
  • 在中括号中添加^就表示取反,即不匹配其中的字符。

关于中括号惟一需要理解的就是:中括号内的字符自带了“|”(或)的属性(这句话是我瞎编的),不管中括号里面有多少个字符,在不加修饰的情况下都只会匹配其中的一个字符(所谓的匹配就是目标字符串与正则表达式有交集(如果有起始符合结束符则表示相同)),只会匹配一个字符未免太小气了,接下来的大括号就是为了解决这个问题的。

2.2. 大括号

“{}”的内容为一对数字范围,意义为指定从方括号“[]”中匹配字符的个数。“一对数字”也只是一个相对的说法: 可以是{n}(匹配固定数目); 或者是{,n}(从0到某个数字的范围); 或者是{n,}(某个数字到正无穷的范围); 或是{n1,n2}(某个闭合区间); 此外还有三种简写方式:

  • “*”表示{,}即不指定次数,匹配存在0个或多个;
  • “+”表示{1,}即至少存在一个;
  • “?”表示{0,1}即存在0个或者1个;

上面提到的这些字符,[{^$|?*+.}],都是正则表达式中的元字符(小括号后面再谈),如果想匹配他们的原本含义字符,需要加上转义符,也就是“\”,当然转义符本身也是一个元字符。

2.3. 中场练习

结合中括号和大括号,以及起始符与结束符就可以完成大部分的正则表达式书写。下面来做一些练习(这些练习题都是我自己瞎想的,有部分重复的地方也懒得改了,这个笔记都快过去一个月了,最近连续加班一周,泪奔):

    //1.检测是否存在子字符串xyz
            var re = /xyz/;
    //2.检测是否是以xy开头的字符串
            var re = /^xyz/;
    //3.检测是否以xyz结束
            var re = /xyz$/;
    //4.匹配是否存在b-h之间的字符
            var re = /[b-h]/;
    //5.匹配是否存在连续三个在b-h之间的字符
            var re = /[b-h]{3}/;
    //6.匹配开头5位是数字的字符串
            var re = /^[0-9]{5}/;
    //7.匹配长度为5位的数字
            var re = /^[0-9]{5}$/;
    //8.匹配长度在3-5位的数字
            var re = /^[0-9]{3,5}$/;
    //9.匹配前三位为字母,后四位为数字的字符串
            var re = /^[a-z]{3}[0-9]{4}$/;
    //10.匹配不区分大小写开头的字符串
            var re = /^[a-zA-Z]/;
    //11.匹配以my或者your开头的字符串
            var re = /^my|your/;
    //12.匹配值在0-35之间的的字符串
            var re = /^([0-9]|1[0-9]|2[0-5])$/;

从上面的练习得到的收获是:

  • 如果是为了获取固定长度的字符串(或或者是以XX开头或结尾),则应当使用^与$来表示准确的匹配;如果只是为了获取某个字符串的子串,则不需要使用这两个符号。
  • 中括号与大括号一般组合使用,再结合通配符,即可编写大部分正则表达式。

此外需要注意的两点是:

  • 重复字符是没有记忆性的,比如[abc]{2}表示先匹配”a或者b或者c”,再匹配”a或者b或者c”,与匹配”aa或者ab或者ac或者ba或者bb或者bc或者ca或者cb或者cc“一样。[abc]{2}并不表示只匹配”aa或者bb或者cc“
  • 重复次数的范围可以是开区间,a{1,}表示匹配一个或一个以上的连续字符a。依然是匹配最长字符串。当找到第一个a之后,正则表达式会尝试匹配尽量多个的连续字母a。

2.4. 小括号

然后来看一看小括号“()”。小括号主要有两个作用:改变限定符的作用范围和分组:

  • 改变限定符的作用范围:比如(a|b)c表示ac或者bc,而a|bc表示a或者bc,两者的含义完全不同了;

  • 分组,即创建子表达式,(a[0-5][bc]){3}表示匹配连续出现a[0-5]bc三次的字符串。关于小括号的分组功能远不止这点,现在暂时还没有深入。

      //改变限定符的作用范围
      var s = "apple";
      var re1 = /a|bc/;
      console.log(re1.test(s));//true,匹配到了a
      var re2 = /(a|b)c/;
      console.log(re2.test(s));//false,并没有ac或者bc
    
      //分组
      var re = /(abc){2}/;
      var s1 = "abc";
      console.log(re.test(s1));//false
      var s2 = "abcabc";
      console.log(re.test(s2));//true
      var s3 = "aabbcc";
      console.log(re.test(s3));//false

3. 贪婪匹配与非贪婪匹配

最后来了解一下正则表达式的贪婪匹配和非贪婪匹配,整个正则入门大概就差不多了。

  • 贪婪匹配:正则表达式一般趋向于最大长度匹配,这是正式表达式的默认匹配模式;
  • 非贪婪匹配:匹配到第一个合适的字符就会返回,即匹配尽可能短的字符,在表达式后加上“?”就可以转变的非贪婪模式。

概念区分十分简单,一般需要考虑选择匹配模式的情况出现在使用“*”的情况下。

    var s = "abxyczc";
    var re1 = /ab.*c/;
    console.log(s.match(re1));//abxyczc
    var re2 = /ab.*?c/;
    console.log(s.match(re2));//abxyc

正则表达式的贪婪匹配与贪婪匹配是一个比较重要的知识点,千万不能忽视。