正则表达式

248 阅读7分钟

这是我参与8月更文挑战的第20天,活动详情查看:8月更文挑战

什么是正则表达式

正则表达式:(Regular Expression)用于匹配规律规则的表达式,正则表达式最初是科学家对人类神经系统的工作原理的早期研究,现在在编程语言中有广泛的应用。正则表通常被用来检索、替换那些符合某个模式(规则)的文本。

正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。

正则表达式的作用

  1. 给定的字符串是否符合正则表达式的过滤逻辑(匹配)

  2. 可以通过正则表达式,从字符串中获取我们想要的特定部分(提取)

  3. 强大的字符串替换能力(替换)

正则表达式的测试

在线测试正则:c.runoob.com/front-end/8…

正则表达式语法

创建

在 JavaScript 中,正则表达式也是对象,是一种索引类型。

使用一个正则表达式字面量是最简单的方式。两个 / 是正则表达式的定界符。

var reg = /abc/; (创建方式1, 推荐)

正则表达式字面量在脚本加载后编译。若你的正则表达式是常量,使用这种方式可以获得更好的性能。

调用 RegExp 对象的构造函数,如下所示:

var re = new RegExp("abc"); (创建方式2)

相关正则方法

  1. 字符串的方法:

split() 根据匹配字符串切割父字符串

match() 使用正则表达式与字符串相比较,返回一个包含匹配结果的数组

search() 对正则表达式或指定字符串进行搜索,返回第一个出现的匹配项的下标, 不存在输出-1。

replace() 用正则表达式和字符串直接比较,然后用新的子串来替换被匹配的子串,返回值是一个新的替换后的字符串,原始字符串不受影响

  1. 正则表达式方法:

exec() 查找匹配的字符串,输出到数组中。不论有没有全局修饰符,都只会在找到第一个之后停止

test() 测试当前正则是否能匹配目标字符串, 返回值是布尔值。

String:split

    // split 方法:分割字符串,成为一个数组
    var str = "aa bbb    c dd eeeeee";
    // 使用一个空格字符进行的精确分割
    var arr = str.split(" ");
    console.log(arr); //"aa", "bbb", "", "", "", "c", "dd", "eeeeee"
    
    // 使用正则表达式可以进行模糊匹配分割
    var arr1 = str.split(/\s+/);
    console.log(arr1); //"aa", "bbb", "c", "dd", "eeeeee"

    var str2 = "bbaacaaaadddaeeeeeaaf";
    var arr2 = str2.split(/a+/);
    console.log(arr2); //"bb", "c", "ddd", "eeeee", "f"

String:search

    //search 方法:查询子串在父字符串中出现的位置
    var str = "abcdefg";
    console.log(str.search("cd"));  //2
    console.log(str.search("cdf"));  //-1
    console.log(str.search(/ef/)); //4
    console.log(str.search(/eff/)); //-1

String:match

    // match 方法:在父字符串中去匹配符合的子字符串,将结果输出到数组中
    var str = "abbcccbbbbbddbbbdabbb";
    var arr1 = str.match(/b+/);  //在匹配到第一个之后就结束
    console.log(arr1); // "bb"
    var arr2 = str.match(/b+/g); //如果有全局修饰符 g,会在找到所有匹配的字符串后结束
    console.log(arr2); //"bb","bbbbb","bbb","bbb"
    
    var str1 = "aaaa o  o bbb o     o  aaa";
    var arr1 = str1.match(/o\s+o/g);
    console.log(arr1);  //"o  o", "o     o"

String:replace

    // replace 方法:替换字符串的指定部分,返回值是一个新的替换后的字符串,原始字符串不受影响
    var str = "www.hello.com";
    var str1 = str.replace(/hello/,"byebye");
    console.log(str);  //www.hello.com
    console.log(str1); //www.byebye.com

RegExp:exec

    // exec 方法:查找匹配的字符串,输出到数组中
    // 不论有没有全局修饰符,都只会在找到第一个之后停止
    var str = "aaaabccccbacabc";
    var reg = /abc/;
    var arr = reg.exec(str);
    console.log(arr);
    console.log(arr.index);

image.png

RegExp:test

// test 方法:检测字符串中是否满足正则表达式的匹配规则,返回值是布尔值
    var reg = /abc/;
    console.log(reg.test("aaddccddabcddeeddfff"));

正则表达式的组成

由一些普通字符和一些特殊字符(又叫元字符--metacharacters)组成。普通字符包括大小写的字母和数字,而元字符则具有特殊的含义。

  1. 普通字符 表示正则匹配时,需要进行精确匹配,必须包含这几个字符,顺序不能颠倒,而且要连续书写
    // 普通字符组成的正则
    var reg = /abc/;
    // 表示正则匹配时,需要进行精确匹配,必须包含a、b、c三个字符,并且顺序不能颠倒,而且要连续书写
    console.log(reg.test("asldfjwefabcsld")); //true
  1. 特殊字符 javascript 中常用特殊字符有 ( ) [ ] { } \ ^ $ | ? * + .

若想匹配这类字符必须用转移符号 \ 如:(,^,\

预定义特殊字符:

字符意义
\s一个空白或多个空白
\t制表符 (尽量不要用, 会出现识别问题)
\n回车符
\f换页符
\b空格

字符集

字符集:使用 [] 表示的可能的字符的集合,集合内部可以排列多个匹配字符串的可能性,整个字符集需要匹配的是字符串中的一个字符。只要字符串中出现 [] 中任何字符,就算匹配成功 (多选一).

简单类

多个可能匹配的字符连续书写在一起,只要其中一个匹配成功即可 正则的多个字符对应一个字符,我们可以用 [] 把它们括起来,让 [] 这个整体对应一个字符[abc]

例子:o[usb]t——obt、ost、out

        var reg = /[abc]/;
        console.log(reg.test("eeeb")); //true

指的是如果字符串中存在a, b, c中任意一个就返回true.

范围类

有时匹配的东西过多,而且类型又相同,全部输入太麻烦,我们可以在中间加了个横线。[a-z]、[0-9]、[A-Z]

例子:id[0-9]——id0、id5

        // 范围类:将匹配同一类型且连续在一起的字符写到集合中,中间使用 - 连接
        var reg = /[A-Q]/;
        console.log(reg.test("A123456")); //true

负向类

[] 前面加个元字符进行取反,表示匹配不能为括号里面的字符。eg. [^a]

例子:o[^0-9]t——oat、o?t、o t 指的是只要不是0-9直接的数字都能匹配成功

        // 负向类:取反的意思,不包含字符集内部书写的字符
        var reg = /[^A-Q]/;
        console.log(reg.test("A")); //false

组合类

单一类型或者简单类不能匹配所有结果,可以将多个写法连在一起书写.

允许用中括号匹配不同类型的单个字符。[0-9a-b]

例子:o[0-9a-b]t——oat、o?t、o

        // 组合类:单一类型或者简单类不能匹配所有结果,可以将多个写法连在一起书写
        // 特殊的:如果数字、大写字母、小写字母,按照这种顺序写的完整的范围,可以缩写
        var reg = /[0-9A-Z]/;
        console.log(reg.test("a")); //false

修饰符

  1. g 修饰符用于执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)
        // g 修饰符:可以实现全局查找 
        var str = "aabblsdddbbbdlBBdllbbbbb";
        var reg = /b+/g;
        console.log(str.match(reg));

image.png

  1. i 修饰符用于执行对大小写不敏感的匹配
        // i 修饰符:字母大小写可以不敏感,a 可以匹配 a 或 A
        var str = "aabblsdddbbbdlBBdllbbbbb";
        var reg = /A/ig;
        console.log(str.match(reg));

image.png

边界

^ 检测字符串的开头是否是要匹配的内容 (注意不能紧跟于左中括号的后面, 不然会被当做取反)

$ 检测字符串的结尾是否是要匹配的内容

        // ^  表示限制开头,后面的正则内容匹配的结果必须出现在字符串开始
        var str = "hello ll Javascript";
        console.log(/^hello/.test(str));  //true
        console.log(/^hhello/.test(str)); //false

        // $ 表示限制结尾,前面的正则内容匹配的结果必须出现在字符串结尾
        console.log(/script$/.test(str));   // true
        console.log(/scripthaha$/.test(str)); //false

        // 实际应用中,会同时限制开头和结尾
        console.log(/^hello\s+Javascript$/.test(str)); //false, 因为str中还有ll, 如果str中没有ll会返回true

预定义类

字符意义说明
.[^\n\r]除了换行和回车之外的任意字符
\d[0-9]数字字符
\D[^0-9]非数字字符
\s[ \t\n\x0B\f\r]空白字符
\S[^ \t\n\x0B\f\r]非空白字符
\w[a-zA-Z_0-9]单词字符(所有的字母/数字/下划线)
\W[^a-zA-Z_0-9]非单词字符
// 非回车非换行字符 .
        console.log(/^.+$/.test(`asldjf2830&*^`)); //true
        console.log(/^.+$/.test(`asldjf
        2830&*^`)); //false
        // \d 数字字符 \D 非数字字符
        console.log(/^\d+$/.test(`0123456789`)); //true
        console.log(/^\d+$/.test(`01234z56789`));//false
        console.log(/^\D+$/.test(`askdAK  *&^`)); //true
        console.log(/^\D+$/.test(`askdAK  *&^7`)); //false
        // \s 空白字符 \S 非空白字符
        console.log(/^\s+$/.test(`  1    
        `)); //false
        console.log(/^\s+$/.test(`      
        `));//true
        console.log(/^\S+$/.test(`AJO456`));//true
        console.log(/^\S+$/.test(`AJO  456`));//false
        // \w 单词字符 \W 非单词字符
        console.log(/^\w+$/.test(`abc09_A`)); //true
        console.log(/^\w+$/.test(`abc*09_A`)); //false
        console.log(/^\W+$/.test(`*&^%$ *`));//true
        console.log(/^\W+$/.test(`a*&^%$ *`));//false

量词

字符意义说明
{n}硬性量词对应零次或者n次
{n,m}软性量词至少出现n次但不超过m次(中间不能有空格)
{n,}软性量词至少出现n次(+的升级版)
?软性量词出现零次或一次
*软性量词出现零次或多次(任意次)
+软性量词出现一次或多次(至少一次)
        // {n}  硬性量词   对应前面的内容必须在字符串中出现 n 次连续
        var reg = /^\d{5}$/;
        console.log(reg.test("1234")); //false
        console.log(reg.test("12345")); //true
        console.log(reg.test("123456"));//false

        // {n,m}  软性量词  对应前面的内容必须在字符串中出现 n-m 次连续
        var reg = /^\d{5,7}$/;
        console.log(reg.test("1234"));//false
        console.log(reg.test("12345"));//true
        console.log(reg.test("123456"));//true
        console.log(reg.test("1234567"));//true
        console.log(reg.test("12345678"));//false

        // {n,}  软性量词  对应前面的内容必须在字符串中出现至少 n 次连续
        var reg = /^\d{5,}$/;
        console.log(reg.test("1234"));//false
        console.log(reg.test("12345"));//true
        console.log(reg.test("123456"));//true
        console.log(reg.test("1234567"));//true
        console.log(reg.test("123456789101112"));//true

        // ?  软性量词  {0,1} 表示前面的内容出现 0 次或 1次
        var reg = /^\d?$/;
        console.log(reg.test("1"));//true
        console.log(reg.test(""));//true
        console.log(reg.test("12345"));//false

        // *  软性量词  {0,} 表示前面的内容出现 0 次或 任意次
        var reg = /^\d*$/;
        console.log(reg.test("1"));//true
        console.log(reg.test(""));//true
        console.log(reg.test("12345"));//true

        // +  软性量词  {1,} 表示前面的内容出现 1 次或 以上
        var reg = /^\d+$/;
        console.log(reg.test(""));//false
        console.log(reg.test("1"));//true
        console.log(reg.test("12345"));//true

分组

用中括号表示范围内选择,大括号表示重复次数。

// 分组
        var reg = /^(bye){2}$/; //表示bye这个组合出现2次
        console.log(reg.test("byebye")); //true
        console.log(reg.test("bbyyee")); //false

或操作符

可以使用竖线(|)字符表示或者的关系

//或操作符 | 
        var reg = /^a|bcd$/;    //匹配时,要么匹配以a开头的,要么匹配以 bcd 结尾的
        console.log(reg.test("cbcde")); //false
        console.log(reg.test("acbcde")); //true
        console.log(reg.test("abcd")); //true

        // 如果想在正则中,在两个规则之间只能选其中一个,不能包含其他的开头结尾,需要去讲或运算放到分组里
        var reg = /^(ab|cd)$/;
        console.log(reg.test("abcd"));  //false
        console.log(reg.test("ab")); //true
        console.log(reg.test("cd")); //true

分组的反向引用

反向引用标识是对正则表达式中的匹配组捕获的子字符串进行编号,通过“\编号(在表达式中)”,“$编号(在表达式外)”进行引用。从1开始计数。

表达式内部:

        // 在正则内部可以通过 \1 方式,去对字符串进行反向引用
        console.log(/^([a-z]{3})\1$/.test("byebye")); //true
        console.log(/^([a-z]{3})\1$/.test("byelie")); //false

^([a-z]{3})会匹配一个以三个小写字母开头的字符串, 即bye. \1 取了标号为1的部分进行匹配, 这时匹配的条件就不是三个小写字母了, 而是bye, 因此第一条返回true, 第二条返回false.

表达式外部:

        // 正则表达式以外通过 $1 ,进行字符串的引用
        var str = "123*456".replace(/^(\d{3})\*(\d{3})$/,"$2*$1");  // 456*123

^(\d{3})表示匹配三个数字, *号是特殊符号, 所以要用\转义符转义. 123的编号是1, 456的编号是2, 所以$2指的是456,$1指的是123

其中, replace()的第二个参数可以是一个函数:

        // 第二个参数可以是一个函数
        var str = "123*456".replace(/^(\d{3})\*(\d{3})$/,function (match,$1,$2) {
            return $1 * 3 + "/" + $2 * 2;
        });
        console.log(str);  //  369/912

function()的第一个参数是强制规定的match.

中文字符

匹配中文字符:[\u4e00-\u9fa5]

是编码形式的, 包含简体和繁体.

        var reg = /^[a-z\u4e00-\u9fa5]+$/;
        console.log(reg.test("只有中文的文字内容")); //true
        console.log(reg.test("只有中文的文 字内容")); //false
        console.log(reg.test("只有中文的文a字内容")); //true