一篇文章精通 JS 正则表达式

182 阅读3分钟

JavaScript 中的正则表达式(Regular Expression,简称 RegExp)是一种用于匹配字符串文本的强大工具。通过定义特定的模式,正则表达式可以有效地搜索、替换和验证字符串内容。JavaScript 中正则表达式的构造主要依靠 RegExp 对象和一些内置的方法。在正则表达式中每匹配一段就在字符中消耗被匹配的内容 零宽断言除外。

使用示例

    const text = "JavaScript is great!";
    // 匹配单词 "JavaScript"
    const regex = /javascript/i;
    console.log(regex.test(text)); // true
    // 提取所有单词
    const words = text.match(/\b\w+\b/g); // \b 匹配空格 \w 匹配 英文字母 \b 匹配空格 g 搜索text全部字符,每匹配一次消耗 text 中的匹配字符,直到匹配完 text 全部字符
    console.log(words); // ["JavaScript", "is", "great"]
    // 替换 "great" 为 "awesome"
    const newText = text.replace(/great/i, "awesome");
    console.log(newText); // "JavaScript is awesome!"

创建正则表达式的方式

    // 字面量方式:使用 /pattern/flags 的形式。
    const regex = /hello/i; // 匹配 "hello",忽略大小写

    // 构造函数方式:使用 RegExp 构造函数。
    const regex = new RegExp("hello", "i"); // 匹配 "hello",忽略大小写

常用标志 就是 构造函数正则中的第二个参数,字面量正则中的最后一个字符

    g:全局匹配,即查找所有匹配项。
    i:忽略大小写。
    m:多行匹配。
    s:允许 . 匹配换行符(ES2018 引入)。
    u:启用 Unicode 匹配模式(ES6 引入)。
    y:粘性匹配,仅从正则表达式的 lastIndex 开始匹配(ES6 引入)。

常用正则表达式模式

    .:匹配除换行符外的任意字符。
    \d:匹配数字 [0-9]。
    \D:匹配非数字。
    \w:匹配字母、数字或下划线 [a-zA-Z0-9_]。
    \W:匹配非字母、数字和下划线。
    \s:匹配空白字符(包括空格、制表符等)。
    \S:匹配非空白字符。
    ^:匹配字符串的开头。
    $:匹配字符串的结尾。

字符组和分组

    // 字符组:使用 [] 表示字符组,匹配其中任意一个字符。
    const regex = /[aeiou]/; // 匹配任意元音字母
    // 排除字符组:使用 [^] 表示不包含的字符组。
    const regex = /[^aeiou]/; // 匹配非元音字母
    // 分组:使用 () 进行分组,可以应用量词,也可以用于捕获匹配的子串。
    const regex = /(ab)+/; // 匹配 "ab" 的重复

量词

    *:匹配前面的字符 0 次或多次。
    +:匹配前面的字符 1 次或多次。
    ?:匹配前面的字符 0 次或 1 次。
    {n}:匹配前面的字符恰好 n 次。
    {n,}:匹配前面的字符至少 n 次。
    {n,m}:匹配前面的字符至少 n 次,至多 m 次。

常用方法

    字符串方法:
        str.match(regex):返回匹配结果数组。
        str.replace(regex, replacement):替换匹配的子串。
        str.search(regex):返回匹配的起始索引。
        str.split(regex):根据匹配分割字符串。
    RegExp 对象方法:
        regex.test(str):测试字符串是否匹配正则表达式,返回 truefalse。
        regex.exec(str):执行匹配,返回第一个匹配项的信息。

零宽断言 又称正向前瞻 (?=...)

// `(?=...)` 确实是正则表达式中的**正向前瞻**(positive lookahead)断言,用于检查某个条件是否存在,而不消耗字符。它确保了在当前位置之后必须存在特定的模式。
    const reg = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[A-Za-z\d]+$/ // 判断字符中必需包含  大小写字符,数字
    const str1 = "Aa";
    const str2 = "Aa2";
    console.log(reg.test(str1)); // false 字符串不包含数字
    console.log(reg.test(str2)); // true 字符中包含数字大小写字母

反向前瞻(Negative Lookbehind)(?<!...)

    //   **用法**:用于确保某个模式**不在当前位置之前**存在。
    //   **示例**:`(?<!abc)` 检查当前位置前面是否没有 `abc`。
    const regex = /(?<!abc)def/; 
    const str1 = "abcdef"; 
    // 不匹配,因为前面有abc 
    const str2 = "xyzdef"; 
    // 匹配,因为前面没有abc 
    console.log(regex.test(str1)); // 输出: false 
    console.log(regex.test(str2)); // 输出: true

正向后顾(Positive Lookbehind)(?<=...)

    // **用法**:用于确保某个模式**在当前位置之前**存在。
    // **示例**:`(?<=abc)` 检查当前位置前面是否有 `abc`。
    const regex = /(?<=abc)def/; 
    const str1 = "abcdef"; 
    // 匹配,因为前面有abc 
    const str2 = "xyzdef"; 
    // 不匹配,因为前面没有abc 
    console.log(regex.test(str1)); // 输出: true 
    console.log(regex.test(str2)); // 输出: false

只读组 (?:...)

 // **用法**:与捕获组相似,但不保存匹配的内容。
 // **示例**:`(?:abc)` 与 `(abc)` 相同,但不会捕获 这里的捕获是指 将使用()匹配内容。在使用特定api 例 match 时 会形成一个数组,里面的序列对应括号内容
 const regex = /(?:abc)/; 
 const str = "abcdef"; 
 console.log(regex.test(str)); // 输出: true

贪婪匹配与非贪婪匹配

正则表达式中的贪婪匹配(Greedy Matching)是指默认情况下,正则表达式会尽可能多地匹配字符。例如,正则表达式中的量词(如*+{m,n})默认都是贪婪的,它们会尝试匹配尽可能多的字符,直到不满足条件为止。

  • 在贪婪模式下,.* 会尽量匹配尽可能多的字符,因此 a.*c 会匹配整个字符串 aabac,即 .* 会匹配 ab
  • 如果想要使正则表达式非贪婪匹配(也叫惰性匹配),可以在量词后加上 ?,使其尽可能少地匹配字符。例如,a.*?c
    // 贪婪匹配 例中 .* 尽可能的匹配多了字符 将需要 test 截断的字符也匹配了
    console.log(/this(.*)test/.exec("this is test test test reg")) // [ "this is test test test", " is test test " ]
    // 非贪婪匹配 .* 尽可能少的匹配,判断了 test 当匹配到 test 就没有继续捕获内容了
    console.log(/this(.*?)test/.exec("this is test test test reg")) // [ "this is test", " is " ]