zoukankan      html  css  js  c++  java
  • 正则表达式详解

    检查是否有匹配项

    regexp.test(str):返回true或false
    str.search(regexp):匹配成功则返回第一个匹配项的索引,否则返回-1

    返回所有匹配项

    regexp.exec(str)
    与match方法返回的结果相同,但是可以多次调用exec方法来获取下一个捕获组的信息。在全局模式下也通用,但match方法在全局模式下不会获取捕获组。
    若想匹配多个结果需要多次调用exec方法,下一次查找将从lastIndex位置开始。
    如果匹配成功,返回一个数组,并更新regexp对象的属性。如果匹配失败,exec() 方法返回 null。

    返回的数组将完全匹配成功的文本作为第一项,将正则括号里匹配成功的捕获组填充到数组后面的项中。
    数组的index属性:匹配到的字符的索引值
    数组的input属性:原始字符串
    (正则对象)lastIndex:下一次匹配的起始位置
    (正则对象)ignoreCase、global、multiline:是否使用了相应模式

    str.match(regexp)
    用于匹配检索项,返回一个包含匹配结果的数组。

    如果正则表达式没有 g 标志,则 str.match() 会返回和 RegExp.exec() 相同的结果。而且返回的 Array 拥有一个额外的 input 属性,该属性包含被解析的原始字符串。另外,还拥有一个 index 属性,该属性表示匹配结果在原字符串中的索引
    如果正则表达式包含 g 标志,则该方法返回一个 Array ,它包含所有匹配的子字符串。捕获组不会被返回
    如果没有匹配到,则返回 nul

    替换

    str.replace(regexp|substr, newSubStr|function)

    第一个参数若是正则表达式并指定了g,那么该正则所匹配的所有内容都会被第二个参数替换
    第一个参数是字符串,则仅第一个匹配会被替换。
    该方法并不改变调用它的字符串本身,而只是返回一个新的替换后的字符串。

    基础知识

    简写形式

    d 就是[0-9]。// 表示是一位数字。记忆方式:其英文是digit(数字)。
    D 就是[^0-9]。// 表示除数字外的任意字符。
    w 就是[0-9a-zA-Z_]。// 表示数字、大小写字母和下划线。记忆方式:w是word的简写,也称单词字符。
    W 是[^0-9a-zA-Z_]。// 非单词字符。
    s 是[ 	v
    
    f]。// 表示空白符,包括空格、水平制表符、垂直制表符、换行符、回车符、换页符。记忆方式:s是space character的首字母。
    S 是[^ 	v
    
    f]。 // 非空白符。
    . 就是[^
    
    u2028u2029]。// 通配符,表示几乎任意字符。换行符、回车符、行分隔符和段分隔符除外。记忆方式:想想省略号...中的每个点,都可以理解成占位符,表示任何类似的东西。

    如果要匹配任意字符怎么办?可以使用[dD]、[wW]、[sS]和[^]中任何的一个。

    1.  量词

    {m,} // 表示至少出现m次。
    {m} // 等价于{m,m},表示出现m次。
    ? // 等价于{0,1},表示出现或者不出现。记忆方式:问号的意思表示,有吗?
    + // 等价于{1,},表示出现至少一次。记忆方式:加号是追加的意思,得先有一个,然后才考虑追加。
    * // 等价于{0,},表示出现任意次,有可能不出现。记忆方式:看看天上的星星,可能一颗没有,可能零散有几颗,可能数也数不过来。

    2. 惰性匹配
    量词默认是贪婪型匹配的,也就是会匹配尽可能长的结果。如果我们需要匹配到第一个就停止,那么就要使用惰性匹配,在后面加一个问号:

    {m,n}? 
    {m,}?

    3. 多选分支是惰性的

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

    可以发现只匹配了good就结束了。
    如果更改一下:

    var regex = /goodbye|good/g;
    var string = "goodbye";
    console.log( string.match(regex) ); 
    // => ["goodbye"]

    这次只匹配了goodbye,说明分支结构也是惰性的,即当前面的匹配上了,后面的就不再尝试了。

    4. 匹配开头和结束

    ^ // 匹配开头,在多行匹配中匹配行开头。
    $ // 匹配结尾,在多行匹配中匹配行结尾。

    比如可以将开头和结尾用#替换:

    var result = "hello".replace(/^|$/gm,"#");
    //"#hello#"

    5. 使用括号的几种情况
    1.分组:
    其中括号是提供分组功能,使量词+作用于“ab”这个整体

    /(ab)+/

    2.分支结构
    提供了子表达式的所有可能。

    /(p1|p2)/

    3.提取数据
    比如我们写了这样一个正则

    /d{4}-d{2}-d{2}/

    如果给其中每一项都加上括号的话,后序就可以提取具体信息:

    var reg = /(d{4})-(d{2})-(d{2})/;
    var string = "2017-06-12";
    string.match(reg);
    
    //["2017-06-12", "2017", "06", "12", index: 0, input: "2017-06-12"]

    match方法返回的数组,第一项是整体匹配结果,然后是各个分组(括号里)的匹配内容。因此加上括号可以让我们获取分组的内容。

    注意,这里要是有g标志,只会返回[“2017-06-12”],而不会返回分组信息。

    另外也可以使用正则对象的exec方法:

    var regex = /(d{4})-(d{2})-(d{2})/;
    var string = "2017-06-12";
    regex.exec(string);
    //["2017-06-12", "2017", "06", "12", index: 0, input: "2017-06-12"]

    不含g标志时,match和exec的结果相同。

    同时,也可以使用构造函数的全局属性1至1至9来获取:

    var regex = /(d{4})-(d{2})-(d{2})/;
    var string = "2017-06-12";
    
    regex.test(string); // 一些正则操作
    
    console.log(RegExp.$1); // "2017"
    console.log(RegExp.$2); // "06"
    console.log(RegExp.$3); // "12"

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

    var regex = /(d{4})-(d{2})-(d{2})/;
    var string = "2017-06-12";
    
    var result = stirng.replace(regex,"$2/$3/$1");
    //"06/12/2017"

    在replace的第二个参数中,可以用$1、$2、$3指代对应的分组。
    这里也顺带一提replace第二参数为函数时的用法。此函数有以下几个参数:

    因此这里的替换也可以这样完成:

    var result = string.replace(regex,function(match,year,month,day){
    return month+"/"+day+"/"+year;
    })

    5.反向引用
    也可以在正则本身里引用分组,但是只能引用之前出现的分组,即反向引用。
    比如要写一个正则支持匹配如下三种格式:

    2016-06-12
    2016/06/12
    2016.06.12

    的正则是:

    var regex = /d{4}(-|/|.)d{2}(-|/|.)d{2}/

    其中/和.需要转义。

    虽然匹配了要求的情况,但也匹配”2016-06/12”这样的数据。
    假设我们想要求分割符前后一致怎么办?此时需要使用反向引用:

    var regex = /d{4}(-|/|.)d{2}1d{2}/
    var string = "2016-06/12";
    regex.test(string); //false 

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

    6.不需要被捕获的分组
    由于小括号既可以表示分组又可以表示捕获组,有什么方法能够表示一个小括号只是表示分组而不捕获它呢?只要在括号的开头加上?:即可:

    var reg = /((?:ninja-)+)sword/;
    var ninjas = "ninja-ninja-sword".match(reg);
    //ninjas[0]:"ninja-ninja-sword"
    //ninjas[1]:"ninja-ninja-"

    可以看到只不活了最外面的括号中的内容,最里面的括号并没有被捕获。

    实战案例
    匹配16进制颜色值

    /#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})/g

    其中的字符可以出现三次或六次

    匹配时间
    24小时制的,如23:59 、02:01

    /^([01][0-9]|[2][0-3]):[0-5][0-9]$/

    注意表示小时的前两位数,当第一位为0或1时,第二位可以是0-9,但是第一位为2时,后面只能是0-3.

    匹配日期 yyyy-mm-dd
    年,四位数字即可,可用[0-9]{4}。

    月,共12个月,分两种情况01、02、……、09和10、11、12,可用(0[1-9]|1[0-2])。

    日,最大31天,可用(0[1-9]|[12][0-9]|3[01])。

    /^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/

    注意是要一位一位匹配!像25这种日期需要使用[1-2][0-9]|来匹配,一开始写了[1-31]的我是个傻子……

    匹配id
    要求从<div id="container" class="main"></div>中提取出id=”container”。
    可能最开始想到的正则是:/id=".*"/,但是首先通配符.就是包含双引号的,其次*则会贪婪匹配,因此最后匹配的结果会是id="container" class="main".

    可以改用惰性匹配:/id=".*?"/
    也有另一种效率高的方法:/id="[^"]*"/ (网易2018秋招笔试中出现类似题目了),也就是在双引号中匹配的任意字符中除去双引号。

    数字的千位分隔符
    比如把”12345678”,变成”12,345,678”。

    这里要使用到(?=p),其中p是一个子模式,即p前面的位置。比如(?=l),表示’l’字符前面的位置。

    var result = "hello".replace(/(?=l)/g, '#');
    // "he#l#lo"

    这样针对千位分隔符,我们可以先弄出最后一个逗号:

    var result = "12345678".replace(/(?=d{3}$)/g,',');
    //"12345,678"

    现在试图弄出所有逗号,因为逗号出现的位置,要求后面3个数字一组,也就是d{3}至少出现一次,使用加号:

    var result = "12345678".replace(/(?=(d{3})+$)/g,',');
    console.log(result); 
    // => "12,345,678"

    但是这个模式匹配123456789,会造成 “,123,456,789”的结果,因此要去除开头。
    这里要使用到(?!p),其实就是(?=p)的反模式,即匹配除p之前的其他位置。这里就可以使用(?!^)来除去开头

    var result = "123456789".replace(/(?!^)(?=(d{3})+$)/g,',');
    //"123,456,789"

    字符串trim方法
    匹配到开头和结尾的空白符,然后替换成空字符。

    str.replace(/^s+|s+$/g,'');

    也可以匹配整个字符串,然后使用引用分组来提取中间的内容:

    str.replace(/^s*(.*?)s*$/g,$1);

    将fontFamily这种驼峰表示法改为font-family这种形式:
    使用$1获取前面捕获的内容

    var str = "fontFamily";
    str.replace(/([A-Z])/g,"-$1").toLowerCase();
    //font-family

    同样也可以进行反方向的操作,即把font-family转换为驼峰形式:
    这里可以使用replace第二个参数为函数的形式:

    var str = "font-family";
    str.replace(/-(w)/g,function(match,letter){
    return letter.toUpperCase();
    })
    //"fontFamily"

    虽然这个例子中只有一个匹配,但是replace的这种使用方法中每一个匹配都会调用此函数。

    匹配所有字符,包括换行符
    一般我们使用.来匹配所有字符,但是这个操作符却无法匹配换行符。因此想真正匹配所有字符包括换行符的话,要使用其他方案:

    /[sS]*/

    s匹配所有空白符,S匹配不是空白符的字符,因此最终的结果就是二者匹配所有字符。

    /(.|s)*/

    .匹配除换行符之外的所有字符,s匹配包括换行符在内的空白字符,因此最终的结果是会匹配包含换行符在内的所有字符。

  • 相关阅读:
    strcpy
    Apple Swift中英文开发资源集锦[apple swift resources]
    c/c++指针总结[pointer summary]
    TestPointer
    66. 有序数组构造二叉搜索树[array to binary search tree]
    HDU 2112 HDU Today
    HDU 3790 最短路径问题
    HDU 2544 最短路
    模拟赛 Problem 3 经营与开发(exploit.cpp/c/pas)
    模拟赛 Problem 2 不等数列(num.cpp/c/pas)
  • 原文地址:https://www.cnblogs.com/ljx20180807/p/10161132.html
Copyright © 2011-2022 走看看