美文网首页
不积跬步之第五章--正则的拆分

不积跬步之第五章--正则的拆分

作者: 雨飞飞雨 | 来源:发表于2021-06-17 08:47 被阅读0次

    对于一门语言的掌握程序怎么样?可以有两个角度来衡量:读和写。不仅要求自己能解决问题,还要能看懂别人的解决方案,代码是这样,正在表达式也是这样。

    正则这门语言跟其他语言有一点不同,它通常就是一大堆字符,而没有所谓“语句”的概念。 如何能正确地把一大串正则拆分成一块一块的,成为了破解“天书”的关键。

    这篇文章提供的答案:

    • 结构和操作符的优先级 ?

    结构和操作符

    编程语言一般都有操作符。只要有操作符,就会出现一个问题。当一大堆操作在一起时,先操作谁,又后操 作谁呢?为了不产生歧义,就需要语言本身定义好操作顺序,即所谓的优先级。

    而在正则表达式中,操作符都体现在结构中,即由特殊字符和普通字符所代表的一个个特殊整体。

    JavaScript 正则表达式中,都有哪些结构呢?
    字符字面量、字符组、量词、锚、分组、选择分支、反向引用。
    具体含义简要回顾如下:

    结构 说明
    字面量 匹配一个具体字符,包括不用转义的和需要转义的。比如 a 匹配字符 "a", 又比如 \n 匹配换行符,又比如 . 匹配小数点。
    字符组 匹配一个字符,可以是多种可能之一,比如[0-9],表示匹配一个数字。也有\d的简写形式。另外还有反义字符组,表示可以是除了特定字符之外任何一个字符,比如[^0-9]。表格一个非数字字符,也有\D的简写形式。
    量词 表格一个字符连续出现,比如a{1,3}表示,"a"字符连续出现3次。另外还有常见的简写形式,比如a+表示"a"字符连续出现至少一次。
    匹配一个位置,而不是字符,比如^匹配字符串的开头,又比如\b匹配单词边界。又比如(?=\d)表示数字前面的位置。
    分组 用括号表示一个整体,比如(ab)+表示ab两个字符连续出现多次,也可以使用非捕获分组,(?:ab)。反向引用,比如\2表示引用第二个分组
    分支 多个子表达式多选一,比如`abc bcd,表达式匹配abc或者bcd`字符子串。

    而其中涉及到的操作符有:

    操作符描述 操作符 优先级
    转义符 \ 1
    括号和方括号 (…)(?:…)(?=…)(?!…)[…] 2
    量词限定符 {m}{m,n}{m,}?*+ 3
    位置和序列 ^$\元字符一般字符 4
    管道符(竖杠) ` ` 5

    上面操作符的优先级从上至下,由高到低。

    下面拆分一个例子:
    /ab?(c|de*)+|fg/

    1. 由于括号的存在,所以,(c|de*)是一个整体。
    2. 在其中,由于管道符的存在,里面是一个分支结构。所以c是一个整体,de*是一个整体
    3. de*中由于量词的存在,所以e是一个整体
    4. 同理,整个正则分成了ab?(c|de*)+fg
    5. 由于分支的存在,又整体分为 ab?(c|de*)+fg两个部分。
    image.png

    注意要点:

    关于结构和操作符,还是有几点需要强调:

    1.匹配字符串整体问题

    因为是要匹配整个字符串,我们经常会在正则前后添加^$

    例如要匹配abc或者bcd,如果不小心就可能写成/^abc|bcd$/.

    但是位置字符和字符序列优先级要比竖杠高,故其匹配的结构是:


    image.png

    所以我们这里要写成这样/^(abc|bcd)$/.

    image.png

    可以看出两个的差距。

    2.量词连缀问题

    假设,要匹配这样的字符串:

    1. 每个字符为a,b,c任选其一。
    2. 字符串的长度是3的倍数。

    此时正则不能想当然地写成/^[abc]{3}+/.因为它会报错。

    image.png

    怎么办呢?

    给它加个括号,把前面括起来。

    image.png

    3.元字符转义问题

    所谓元字符,就是正则中有特殊含义的字符。

    所有结构,用到的元字符总结如下:

    ^、$、.、*、+、?、|、\、/、(、)、[、]、{、}、=、!、:、- ,

    当匹配上面的字符本身时,可以一律转义:

    var string = "^$.*+?|\\/[]{}=!:-,";
    var regex = /\^\$\.\*\+\?\|\\\/\[\]\{\}\=\!\:\-\,/;
    console.log( regex.test(string) );
    // => true
    

    其中string中的\字符也是要转义的。

    另外,在string中,可以把每个字符转义,当然,转义后的结构仍是本身:

    var string = "^$.*+?|\\/[]{}=!:-,";
    var string2 = "\^\$\.\*\+\?\|\\\/\[\]\{\}\=\!\:\-\,";
    console.log( string == string2 );
    // => true
    

    4.字符串中的元字符

    更字符组相关的元字符,如果需要匹配,也需要进行转义。

    var string = "^$.*+?|\\/[]{}=!:-,";
    var regex = /[\^$.*+?|\\/\[\]{}=!:\-,]/g;
    console.log( string.match(regex) );
    // => ["^", "$", ".", "*", "+", "?", "|", "\", "/", "[", "]", "{", "}", "=", "!", ":",
    "-", ","]
    

    5.匹配[abc]{3,5}

    如果要匹配[abc]{3,5}.

    可以写成/\[abc]/或者/\[abc]/.

    var string = "[abc]";
    var regex = /\[abc]/g;
    console.log( string.match(regex)[0] );
    // => "[abc]"
    

    只需要转义第一个方括号就可以,因为后面的构不成字符组。

    而匹配{3,5}则使用/\{3,5}/.

    6.其余情况

    比如=,!,:,-,,等符号,只要不在特殊结构中,并不需要转义。

    但是,括号需要前后都转义/\(123)/

    至于剩下的 ^、$、.、*、+、?、|、\、/等字符,只要不在字符组内,都需要转义的。

    相关文章

      网友评论

          本文标题:不积跬步之第五章--正则的拆分

          本文链接:https://www.haomeiwen.com/subject/yshxyltx.html