美文网首页js css html
简单正则入门

简单正则入门

作者: 没名字的某某人 | 来源:发表于2021-08-11 14:48 被阅读0次

    写在最前,本文转自掘金

    常用字符

    正则中很多需要强记的字符,这里列出常用的字符和其表达的含义:

    常用匹配字符 含义
    [0-9] 匹配单数组0-9
    [a-z] 匹配单个小写字母
    [A-Z] 匹配单个大写字母
    \s 匹配所有空白字符,如空格、换行等
    \n 匹配所有换行字符
    \b 匹配边界如字符之间的空格
    特殊字符 含义 用法
    ^ 1.匹配输入字符串的开始位置 2.用在[]中是表示 非 1. /^http/ 匹配http开头的字符串 2. /[^a-zA-Z]/ 匹配非字母
    $ 匹配输入字符串的结尾位置 /.com$/匹配以.com结尾的字符串
    | 二选一,表示 或 /a | b/ 匹配a或者b
    . 小数点匹配换行符\n之外的任何单个字符 /./匹配换行符之外的其他字符
    [] 中括号匹配一个字符 /[aeiou]/匹配字母aeiou中的一个
    () 小括号表示一个子表达式分组 匹配的子表达式可以用于以后使用
    {} 大括号表示限定一个表达式多少次 {n}匹配n次 {n,}匹配最少n次 {n,m}匹配n-m次
    + 匹配前面的子表达式一次或多次 /[0-9]+/匹配一个数字或多个数字
    * 匹配前面的子表达式零个或多个 /[0-9]*/匹配0个数字或多个数字
    ? 1.匹配前面的子表达式零次或一次 2.指明一个非贪婪限定符 1./[0-9]?/ 2./<.*?>/匹配一个标签如<p>

    匹配特殊字符本身时需要转义,共有一下几个:
    * . ? + $ ^ [ ] ( ) { } | \ /

    • 其中 / 在字面量中需要转义,在构造函数中不需要,如下匹配一个斜杠 /
    const reg = /\//
    const reg = new RegExp('/')
    
    • 在字面量中带一个转义符 \ 的用构造函数写要带两个转义符 \\ ,如下匹配一个字符串.
    const reg = /\./
    const reg = new RegExp('\\.')
    

    常用方法

    js 中的正则表达式分为字面量和构造函数两种:

    // 字面量
    const reg = /[0-9a-z]/g
    // 构造函数
    const reg = new RegExp('[0-9z-a]', 'g')
    

    其中字面量中不能包含变量,构造函数中可以使用变量:

    const name = '我是饼干'
    const reg = new RegExp(`我的名字叫${name}`)
    

    经常会用reg.test(str)方法来判断字符串中是否匹配到了正则表达式:

    const = reg = /[0-9]/
    const str = '文本中有没有数字1234等'
    if(reg.test(str)){
     ...
    }
    

    也经常用 str.replace(reg, '')方法来替换字符串中的内容:

    const reg= /[0-9]/g
    const str = '文本中的数字1234全部替换成x'
    const newStr = str.replace(reg, 'x')
    

    也会用到str.match(reg)方法来获取匹配到的内容(也可用reg.exec(str)):

    const reg = /[0-9]+[.][0-9]+[.][0-9]+/g
    const str = '这里有个表名叫做 11.11.11'
    str.match(reg) //['11.11.11']
    
    • match 中的正则表达式如果使用g标志,则表示返回与完整正则表达式匹配的所有结果,但不会返回捕获组(Array)。在这种情况下,返回的项目将具有如下所述的其他属性。

    贪婪&非贪婪

    *和+限定符都是贪婪的,她们会尽可能多的匹配文字。在它们的后面加上一个?就可以实现非贪婪或最小匹配。

    • 贪婪(默认都是贪婪的)
    const str = '<h1>正则表达式</h1>'
    const reg = /<.*>/
    str.match(reg) //   ['<h1>正则表达式</h1>']
    

    捕获分组和回溯引用

    小括号()匹配到的子表达式会被缓存为一个个组,方便后面对其引用。假设要获取html中的h1标签:

    • 在正则表达式中使用\n 可以引用第n个捕获组
    const str = '<p>正则表达式</p><h1>正则表达式</h1><h2>正则表达式</h2>'
    const reg = /<(h1)>.+?<\/\1>/
    str.match(reg) // ['<h1>正则表达式</h1>']
    
    • 在正则表达式外使用 $n 引用第n个捕获组(RegExp.$n)
    const str = 'abc'
    const reg = /(abc)/
    RegExp.$1 // 'abc'
    str.replace(reg, '$1$1') // 'abcabc'
    

    非捕获分组和限定查找

    因为捕获组()会将每个捕获到的结果缓存下来以便引用,所以造成内存使用增加。如果只想用分组的原始功能,而不需要缓存,则可以使用非捕获组(?:)

    const str = 'abc'
    const reg = /(?:abc)/
    RegExp.$1 // ''
    

    非捕获分组还有 (?=)、(?<=)、(?!)、(?<!),他们比(?:)多了限定作用,即只匹配而不会被输出。

    前向查找

    前向查找是用来限制后缀的

    1. (?=) 即查找符合限定条件 (?=) 的前面的匹配项(输出内容不包括(?=)中的匹配项)
    const str = 'a.png b.jpg c.gif d.svg'
    // 查找所有 边界开头的、 .svg 前面的 小写字母。
    const reg = /\b[a-z](?=.svg)/g
    str.match(reg) // ['d']
    
    1. (?!) 即查找 不符合 限定条件 (?!) 的前面的匹配项(输出内容不包括(?!)中的匹配项)
    const str = 'a.png b.jpg c.gif d.svg'
    // 查找所有边界开头的、 非.svg 前面的、 `.[a-z]{3}` 前面的 小写字母。
    const reg = /\b[a-z](?!.svg)(?=\.[a-z]{3})/g
    str.match(reg) // ['a', 'b', 'c']
    

    后向查找

    后向查找是用来限制前缀的

    1. 查找符合限定条件 (?<=) 的后面的匹配项(输出内容不包括(?<=)中的匹配项)
    const str = '1. 1111; 2. 2222; 3. 3333; 4. 4444。'
    //  查找所有 序号 后面的项。
    const reg = /(?<=\b[0-9]+\.\s).+?[;。]/g
    str.match(reg) // ["1111;", "2222;", "3333;", "4444。"]
    
    1. 查找 不符合 限定条件 (?<!) 的后面的匹配项(输出内容不包括(?<!)中的匹配项)
    const str = 'a.png b.jpg c.gif d.svg'
    // 查找前缀不为 a b c 的后面的项
    const reg = /\b(?<![abc]\.)[a-z]{3}/g
    str.match(reg) // ['svg']
    

    举个例子

    一般稍微复杂的正则都是多种规则同时使用的,下面来几个例子吧:

    前向查找和后向查找齐用

    假设要获取 <img crossorigin src="https://abcdefg.com" data-img-url="https://test.com"> 中的 data-img-url 属性中的链接。可以确定的是链接左边一定是 data-img-url=" ,右边一定是紧贴着 " (非贪婪)。

    const str = '<img crossorigin src="https://abcdefg.com" data-img-url="https://test.com">'
    const reg = new RegExp(`(?<=data-img-url=").+?(?=")`,'g')
    str.match(reg)  // ['https://test.com']
    

    回溯引用和非贪婪并用

    假如我要获取一段html中的文本,但是我又不想要加了 not-show-in-text 标记的标签中的文本,可以这样

    const notShowInText = 'not-show-in-text'
    const html = `
      <p>test1</p>
      <p ${notShowInText} style="text-align: center;">
        <b>表 1.4.4 测试表格</b>
      </p>
      <p>test2</p>
    `
    const reg = new RegExp(`<([a-z][a-z1-6]*?)[^>]+${notShowInText}[\\s\\S]+?</\\1>`, 'g')
    const text = html.replace(reg, '').replace(/<[^>]+>/g, '')
    

    其中最关键的是要匹配到 not-show-in-text 所在的整个标签。([a-z][a-z1-6]*?) 匹配了一个非贪婪的标签名,[^>] 保证了 <> 是一个半个完整的标签,</\\1> 匹配一个闭合的标签, [\\s\\S]+? 匹配了标签见可能出现的任意元素且是非贪婪的。

    replace第二个参数可以是回调函数

    比如,想把yyyy-mm-dd 格式,替换成yyyy/mm/dd

    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指代相应的分组。等价于如下的形式:

    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"
    

    也等价于:

    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"
    

    相关文章

      网友评论

        本文标题:简单正则入门

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