JS-正则表达式

语法

  • \d可以匹配一个数字,等价于[0-9]
  • \w可以匹配一个单字字符 (字母、数字或者下划线) ,等价于[A-Za-z0-9_]
  • \W匹配一个非单字字符,等价于[^A-Za-z0-9_]
  • .可以匹配一个任意字符换行符除外
  • \s匹配一个空白字符,包括空格制表符换页符换行符
  • \S匹配一个非空白字符
  • *表示任意个字符,等价于 {0,}
  • +表示至少一个字符,等价于 {1,}
  • ?表示0个或1个字符,等价于 {0,1}
  • {n}表示n个字符
  • {n,m}表示n-m字符
  • \转义
  • (x)普通分组,匹配 'x'并且记住匹配项
  • (?<组名>RegExp)具名组,使用$<组名>引用具名组
  • [xyz]一个字符集合
  • [^xyz]一个反向字符集
  • A|B可以匹配AB
  • ^表示行的开头非的意思
  • $表示行的结束


分组(或捕获组)

正则表达式通过使用括号表达式分为不同的分组,识别的方法是通过从左至右搜寻左半括号,遇到第一个左半括号时,则该左半括号与对应的右半括号所包含的内容即为第一分组,以此类推 。

例如,在表达式((A)(B(C))),有四个这样的组:((A)(B(C)))、(A)、(B(C))、(C)


具名组

  • 字符串替换时,使用$<组名>引用具名组

    1
    2
    3
    let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;

    '2015-01-02'.replace(re, '$<day>/$<month>/$<year>');
  • 正则表达式内部引用某个“具名组匹配”,可以使用\k<组名>,或者数字引用\1

    1
    2
    3
    4
    5
    const RE_TWICE = /^(?<word>[a-z]+)!\k<word>!\1$/;

    RE_TWICE.test('abc!abc!abc') // true

    RE_TWICE.test('abc!abc!ab') // false


位置类元数据

  • (exp)目标字符串需要匹配exp,并将该分组匹配的子文本保存到自动命名的组里;
  • (?<name>exp)目标字符串需要匹配exp,并将该分组匹配的子文本保存到名称为name的组里,也可以写成(?'name'exp)
  • (?:exp)目标字符串需要匹配exp,该括号所包括的内容不会被作为一个分组对待,该表达式与(exp)在效果上其实应该是没有区别的,区别只是是否算作一个分组及是否保存匹配的子文本
  • (?=exp) :定义目标字符串结束位置要求,即紧随目标字符串后面出现的字符串需要匹配上exp表达式,该字符串不会被计入目标字符串,表达中出现的括号也不会被视作一个分组
  • (?<=exp):定义目标字符串起始位置要求,即紧邻目标字符串前面出现的字符串需要匹配上exp表达式,该字符串不会被计入目标字符串,表达中出现的括号也不会被视作一个分组
  • (?!exp):定义目标字符串结束位置要求,即紧随目标字符串后面出现的字符串不能匹配exp表达式,该字符串不会被计入目标字符串,表达中出现的括号也不会被视作一个分组;效果上与(?=exp) 表示的情况刚好相反;
  • (?<!exp):定义目标字符串起始位置要求,即紧邻目标字符串前面出现的字符串不能匹配exp表达式,该字符串不会被计入目标字符串,表达中出现的括号也不会被视作一个分组;效果上与(?<=exp)表示的情况刚好相反;
1
str.replace(/(\d)(?=(?:\d{3})+$)/g, '$1,'); // 千分位


贪婪匹配

贪婪匹配指的是:匹配的子串是最长的,如果符合条件,就一直匹配,返回最长的匹配子串。

非贪婪匹配:如果匹配成功,就返回子串,而不继续向下匹配了,用法就是在量词后面加上一个?

1
2
3
4
5
6
7
var str = "aaabbb";
var reg = /a+/g;
console.log(str.match(reg)); // ["aaa"]

// 改为非贪婪匹配,用?,能匹配一次绝对不匹配多次
var reg = /a+?/g;
console.log(str.match(reg)); // ["a","a","a"]