JavaScript正则表达式学习

本文是JS正则表达式完整教程(略长)的学习笔记。

正则表达式的创建

  1. const re = /abcd/
  2. const re = new RegExp(‘abcd’)

其中,abcd表示要匹配的模式。

一个字符匹配多次和从多个字符中匹配一个

  • 一个字符匹配多次

    要想把一个字符匹配多次,我们可以使用大括号中包含范围的方法来表示,形式如下:

    const re = /abc{1,100}d/

    这个正则就表示,将c匹配1到100次。也就是说,这个正则既能匹配到像abcd这样的字符串,也能匹配到像abccd甚至更多的c的字符床,只要c的个数不超过100个。其中的1和100我们可以根据需要,随意替换成我们需要的范围,下面为了方便表示说明,我们用{m,n}来表示说明。

    m表示下限,n表示上限,当只出现m不出现n时{m,}表示对应的字符串出现m以上的次数,当只出现m时{m}表示对应的字符出现m次。另外,还有三个对应的简易用法,用符号来表示对应的范围。

    1.?等价于{0,1}。
    
    1. +等价于{1,}。即对应的字符串出现1次到正无穷次
    2. *等价于{0,}。即对应的字符串出现0到正无穷次。
  • 多个字符中匹配一个

    这种形式就是,我们想从多个字符中匹配一个。比如我们想匹配在一个字符串中匹配a,b,c,d,e。我们可以用如下方式,[abcde]这样,举个例子

    const re = /test[abcde]/在这个正则表达式中,我们就可以匹配testa,testb,testc,testd,teste。

多个匹配模式

既然可以匹配一个或者多个字符,强大的正则照样可以匹配一个或者多个模式。实现形式是/p1|p2|p3/其中p1,p2,p3就是三个独立的模式。

比如

1
2
3
4
var regex = /good|nice/g;
var string = "good idea, nice try.";
console.log( string.match(regex) );
// => ["good", "nice"]

匹配的简易写法

当我们需要匹配多个字符中的一个时,我们可以用[abcdef···]这样的方法来实现,但是不免显得比较啰嗦,所以我们需要一个简写模式。

  1. 当我们想匹配任意字母表中的一个时,我们可以用[a-z],这样,我们就把所有小写字母都匹配了。相应的,当我们想匹配所有大写字母时,我们就写成[A-Z],这样,所有的大写字母就都匹配上了。接下来就是所有数字了,我觉得其实已经可以猜到怎么匹配所有的数子了吧,没错就是[0-9]。

    有的时候,我们还想匹配“-”符号,这个时候,可以把它放在开头或者末尾,这样就不表示范围了。当然还可以放在中间,但是需要加一个转义符号“\”。

  2. 我们有啥都想要的时候,也有啥都不想要的时候,当我们不想要时,就可以用[^abc]来表示了,这个也可以用范围表示法来表示。

    3.你以为范围表示法够简便了吧?其实不是,还有更简便的,接下来我们继续人事一下。

  • \d 等价于[0,9],所有数字中的一个;

  • \D等价于[^0,9],表示除了数字外的一切;

  • \w等价于[0-9a-zA-Z],表示数字,字母以及下划线;

  • \W等价于[^0-9a-zA-Z],表示非单词字符。

  • \s表示[ \t\v\n\r\f]。表示空白符,包括空格、水平制表符、垂直制表符、换行符、回车符、换页符。

  • \S[^ \t\v\n\r\f]。 非空白符。

  • ·通配符,表示几乎任意字符。换行符、回车符、行分隔符和段分隔符除外。

    现在,你想匹配任意字符时,就可以用[\d\D][\w\W][\s\S][^]`中任何的一个来实现了。

贪婪匹配和惰性匹配

贪婪匹配就是尽可能多的匹配,有多少收多少;惰性匹配则是匹配到第一个后,就不动了,任你千军万马,我也不去管了。

默认的都是贪婪匹配,要想实现惰性匹配,只需要在匹配的次数后面添加一个“?”就可以了。

在某个位置匹配

^匹配开头,在多行匹配中匹配行开头。

$匹配结尾,在多行匹配中匹配行结尾。

\b是单词边界,具体就是\w\W之间的位置,也包括\w^之间的位置,也包括\w$之间的位置。

\B非单词\b的反面意思,非单词边界。

(?=p),其中p是一个子模式,即p前面的位置。

(?!p)就是(?=p)的反面意思

在正则中使用括号

1.分组

我们已经学习过如何匹配一个字符出现一次或者多次的情况,但是如何匹配多个字符出现一次或者多次的情况呢?

这个我们需要用到括号了,只需要将需要匹配且多次出现的符号用括号括起来,就可以实现了。如下:const re = /a(bc){0,6}/这样,就可以匹配bc出现多次的情况了,如字符床abcbcd。

2.结合之前多个字符的经验,多个模式也是可以用括号来实现了。如: const re = /a(b|c|d)/这样,就可以匹配ab或者ac或者ad了。

3.与match或者exec结合,提取数据。

match返回的一个数组,第一个元素是整体匹配结果,然后是各个分组(括号里)匹配的内容,然后是匹配下标,最后是输入的文本。(注意:如果正则是否有修饰符gmatch返回的数组格式是不一样的)。

另外也可以使用正则对象的exec方法,也可以使用构造函数的全局属性$1$9来获取。

4.替换

比如,想把yyyy-mm-dd格式,替换成mm/dd/yyyy怎么做?

1
2
3
4
5
6
var regex = /(\d{4})-(\d{2})-(\d{2})/;
var string = "2017-06-12";
var result = string.replace(regex, "$2/$3/$1");
console.log(result);
// => "06/12/2017"
复制代码

其中replace中的,第二个参数里用$1$2$3指代相应的分组。等价于如下的形式:

1
2
3
4
5
6
7
8
var regex = /(\d{4})-(\d{2})-(\d{2})/;
var string = "2017-06-12";
var result = string.replace(regex, function() {
return RegExp.$2 + "/" + RegExp.$3 + "/" + RegExp.$1;
});
console.log(result);
// => "06/12/2017"
复制代码

也等价于:

1
2
3
4
5
6
7
var regex = /(\d{4})-(\d{2})-(\d{2})/;
var string = "2017-06-12";
var result = string.replace(regex, function(match, year, month, day) {
return month + "/" + day + "/" + year;
});
console.log(result);
// => "06/12/2017"

3.反响引用

除了使用相应API来引用分组,也可以在正则本身里引用分组。但只能引用之前出现的分组,即反向引用。

还是以日期为例。

比如要写一个正则支持匹配如下三种格式:

2016-06-12

2016/06/12

2016.06.12

最先可能想到的正则是:

1
2
3
4
5
6
7
8
9
10
var regex = /\d{4}(-|\/|\.)\d{2}(-|\/|\.)\d{2}/;
var string1 = "2017-06-12";
var string2 = "2017/06/12";
var string3 = "2017.06.12";
var string4 = "2016-06/12";
console.log( regex.test(string1) ); // true
console.log( regex.test(string2) ); // true
console.log( regex.test(string3) ); // true
console.log( regex.test(string4) ); // true
复制代码

其中/.需要转义。虽然匹配了要求的情况,但也匹配”2016-06/12”这样的数据。

假设我们想要求分割符前后一致怎么办?此时需要使用反向引用:

1
2
3
4
5
6
7
8
9
10
var regex = /\d{4}(-|\/|\.)\d{2}\1\d{2}/;
var string1 = "2017-06-12";
var string2 = "2017/06/12";
var string3 = "2017.06.12";
var string4 = "2016-06/12";
console.log( regex.test(string1) ); // true
console.log( regex.test(string2) ); // true
console.log( regex.test(string3) ); // true
console.log( regex.test(string4) ); // false
复制代码

注意里面的\1,表示的引用之前的那个分组(-|\/|\.)。不管它匹配到什么(比如-),\1都匹配那个同样的具体某个字符。

我们知道了\1的含义后,那么\2\3的概念也就理解了,即分别指代第二个和第三个分组。

和正则匹配使用的相关API

  • search

    用来搜索指定的字符串或者指定的正则。会返回匹配到的字符串或者正则表达式的位置。匹配不到时会返回-1.

  • test

    检测字符串是否匹配某个模式,如果匹配返回true,否则返回false。

  • match

    在字符串内检索指定的值或者正则表达式,返回匹配到的数组,如果没有匹配到则返回null。

  • exec

    方法用于检索字符串中的正则表达式的匹配。如果字符串中有匹配的值返回该匹配值,否则返回 null。

  • split

    用于将一个字符串按照某个字符或者正则分割成数组。

  • replace

    方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。

正则表达式中的修饰符

g 全局匹配,即找到所有匹配的,单词是global

i 忽略字母大小写,单词ingoreCase

m 多行匹配,只影响^$,二者变成行的概念,即行开头和行结尾。单词是multiline