创建正则表达式的方法

  1. /ab+c/i; //字面量形式
  2. new RegExp('ab+c', 'i'); // 首个参数为字符串模式的构造函数
  3. new RegExp(/ab+c/, 'i'); // 首个参数为常规字面量的构造函数

.search和.match方法

.search 如果找到则返回第一个字母的index, 未找到则返回-1
.match 返回于正则匹配的项

  1. let str = "I love mp3"; // 将在这里搜索
  2. let regexp = /love/;
  3. alert( str.search(regexp) ); // 2
  4. alert( str.match(/\s\w\w\d/) ); // mp3

修饰符

  • i ——不区分大小写
  • g —— 查找所有匹配项
  • m ——多行模式
  • u ——完整unicode支持
  • y ——粘滞模式
  • s ——让.匹配任何字符

字符类

  • \d ——数字
  • \D ——非数字
  • \s ——空格,制表符,换行符
  • \S ——除了\s
  • \w ——拉丁字母, 数字,下划线_
  • \W —— 除了\w
  • . ——除了换行符\n之外的所有字符

匹配所有字符的方法

.s修饰符

  1. /./s

\s + \S

  1. /[\s\S]/

unicode

修饰符 u 在正则表达式中提供对 Unicode 的支持。
这意味着两件事:

  1. 4 个字节长的字符被以正确的方式处理:被看成单个的字符,而不是 2 个 2 字节长的字符。
  2. Unicode 属性可以被用于查找中 \p{…}

有了 unicode 属性我们可以查找给定语言中的词,特殊字符(引用,货币)等等。

  1. let regexp = /\p{Sc}\d/gu;
  2. let str = `Prices: $2, 1, ¥9`;
  3. alert( str.match(regexp) ); // $2,€1,¥9

锚点

插入符号 ^ 匹配文本开头,而美元符号 $ - 则匹配文本末尾
^…$用于完全匹配

  1. let goodInput = "12:34";
  2. let badInput = "12:345";
  3. let regexp = /^\d\d:\d\d$/;
  4. alert( regexp.test(goodInput) ); // true
  5. alert( regexp.test(badInput) ); // false

m修饰符开启多行匹配

  1. let str = `1st place: Winnie
  2. 2nd place: Piglet
  3. 33rd place: Eeyore`;
  4. alert( str.match(/\w+$/gim) ); // Winnie,Piglet,Eeyore

词边界:\b

有三种不同的位置可作为词边界:

  • 在字符串开头,如果第一个字符是单词字符 \w
  • 在字符串中的两个字符之间,其中一个是单词字符 \w,另一个不是。
  • 在字符串末尾,如果最后一个字符是单词字符 \w。 ```javascript alert( “Hello, Java!”.match(/\bHello\b/) ); // Hello alert( “Hello, Java!”.match(/\bJava\b/) ); // Java alert( “Hello, Java!”.match(/\bHell\b/) ); // null (no match) alert( “Hello, Java!”.match(/\bJava!\b/) ); // null (no match)

// 也可以匹配数字 alert( “1 23 456 78”.match(/\b\d\d\b/g) ); // 23,78 alert( “12,34,56”.match(/\b\d\d\b/g) ); // 12,34,56

  1. <a name="hMm3Q"></a>
  2. ### 转义
  3. - 要在字面(意义)上搜索特殊字符 `[ \ ^ $ . | ? * + ( )`,我们需要在它们前面加上反斜杠 `\`(“转义它们”)。
  4. - 如果我们在 `/.../` 内部(但不在 `new RegExp` 内部),还需要转义 `/`。
  5. - 传递一个字符串(参数)给 `new RegExp` 时,我们需要双倍反斜杠 `\\`,因为字符串引号会消费其中的一个。
  6. ```javascript
  7. let regStr = "\\d\\.\\d";
  8. alert(regStr); // \d\.\d (correct now)
  9. let regexp = new RegExp(regStr);
  10. alert( "Chapter 5.1".match(regexp) ); // 5.1

集合和范围[…]

[eao] 意味着查找在 3 个字符 'a''e' 或者 `‘o’ 中的任意一个, 这被叫做一个集合。
请注意尽管在集合中有多个字符,但它们在匹配中只会对应其中的一个

  1. // 查找 [t 或者 m],然后再匹配 “op”
  2. alert( "Mop top".match(/[tm]op/gi) ); // "Mop", "top"

方括号也可以包含字符范围
比如说,[a-z] 会匹配从 az 范围内的字母,[0-5] 表示从 05 的数字。

  1. alert( "Exception 0xAF".match(/x[0-9A-F][0-9A-F]/g) ); // xAF

除了普通的范围匹配,还有类似 [^…] 的“排除”范围匹配。
它们通过在匹配查询的开头添加插入符号 ^ 来表示,它会匹配所有除了给定的字符之外的任意字符。

  1. alert( "alice15@gmail.com".match(/[^\d\sA-Z]/gi) ); // @ and .

在[…]中不需要转义[-().^+] 会查找 -().^+ 的其中任意一个字符。

量词

用来形容我们所需要的数量的词被称为量词

{n}

\d{5} 表示 5 位的数字,如同 \d\d\d\d\d
\d{3,5}查找位数为 3 至 5 位的数字
\d{3,} 查找位数大于或等于 3 的数字

+

代表“一个或多个”,相当于 {1,}

?

代表“零个或一个”,相当于 {0,1}

*

代表着“零个或多个”,相当于 {0,}

贪婪模式 vs 懒惰模式

  • 贪婪模式:默认情况下,正则表达式引擎会尝试尽可能多地重复量词。例如,\d+ 检测所有可能的字符。当不可能检测更多(没有更多的字符或到达字符串末尾)时,然后它再匹配模式的剩余部分。如果没有匹配,则减少重复的次数(回溯),并再次尝试。
  • 懒惰模式通过在量词后添加问号 ? 来启用。在每次重复量词之前,引擎会尝试去匹配模式的剩余部分。

    捕获组

    括号将正则表达式的一部分组合在一起,以便量词可以整体应用。
    1. alert( 'Gogogo now!'.match(/(go)+/i) ); // "Gogogo"
    括号组从左到右编号,可以选择用 (?<name>...) 命名。 ```javascript let dateRegexp = /(?[0-9]{4})-(?[0-9]{2})-(?[0-9]{2})/; let str = “2019-04-30”;

let groups = str.match(dateRegexp).groups;

alert(groups.year); // 2019 alert(groups.month); // 04 alert(groups.day); // 30

  1. 可以在结果中获得按组匹配的内容:
  2. - 方法 `str.match` 仅当不带标志 `g` 时返回捕获组。
  3. 1. 在索引 `0` 处:完全匹配。
  4. 2. 在索引 `1` 处:第一个括号的内容。
  5. 3. 在索引 `2` 处:第二个括号的内容。
  6. 4. …等等…
  7. ```javascript
  8. let str = '<h1>Hello, world!</h1>';
  9. let tag = str.match(/<(.*?)>/);
  10. alert( tag[0] ); // <h1>
  11. alert( tag[1] ); // h1
  • 方法 str.matchAll 始终返回捕获组。

matchAll返回的不是数组,而是一个可迭代的伪数组

  1. let results = '<h1> <h2>'.matchAll(/<(.*?)>/gi);
  2. // results - is not an array, but an iterable object
  3. alert(results); // [object RegExp String Iterator]
  4. alert(results[0]); // undefined (*)
  5. results = Array.from(results); // 转换为真正的数组
  6. alert(results[0]); // <h1>,h1 (1st tag)
  7. alert(results[1]); // <h2>,h2 (2nd tag)

如果括号没有名称,则匹配数组按编号提供其内容。命名括号还可使用属性 groups
我们还可以使用 str.replace 来替换括号内容中的字符串:使用 $n 或者名称 $<name>

  1. let str = "John Bull";
  2. let regexp = /(\w+) (\w+)/;
  3. alert( str.replace(regexp, '$2, $1') ); // Bull, John

可以通过在组的开头添加 ?: 来排除编号组。当我们需要对整个组应用量词,但不希望将其作为结果数组中的单独项时这很有用。我们也不能在替换字符串时引用此类括号。

  1. let str = "Gogogo John!";
  2. // ?: 从捕获组中排除 'go'
  3. let regexp = /(?:go)+ (\w+)/i;
  4. let result = str.match(regexp);
  5. alert( result[0] ); // Gogogo John(完全匹配)
  6. alert( result[1] ); // John
  7. alert( result.length ); // 2(数组中没有更多项)

反向引用:\N 和 \k

按组号反向引用 \N

  1. let str = `He said: "She's the one!".`;
  2. let regexp = /(['"])(.*?)\1/g;
  3. alert( str.match(regexp) ); // "She's the one!"

按命名反向引用 \k

  1. let str = `He said: "She's the one!".`;
  2. let regexp = /(?<quote>['"])(.*?)\k<quote>/g;
  3. alert( str.match(regexp) ); // "She's the one!"

选择(OR)|

我们需要找出编程语言:HTML、PHP、Java 或 JavaScript。
对应的正则表达式为:html|php|java(script)?

  1. let reg = /html|php|css|java(script)?/gi;
  2. let str = "First HTML appeared, then CSS, then JavaScript";
  3. alert( str.match(reg) ); // 'HTML', 'CSS', 'JavaScript'

我们通常用圆括号把模式中的选择部分括起来,像这样 before(XXX|YYY)after

前瞻断言和后瞻断言

x(?=y) 前瞻肯定断言 x ,仅当后面跟着 y
x(?!y) 前瞻否定断言 x ,仅当后面不跟 y
(?<=y)x 后瞻肯定断言 x ,仅当跟在 y 后面
(?<!y)x 后瞻否定断言 x ,仅当不跟在 y 后面

粘性标志 “y”,在指定位置处搜索

标记 y 使 regexp.exec 正好在 lastIndex 位置,而不是在它之前,也不是在它之后。

  1. let str = 'let varName = "value"';
  2. let regexp = /\w+/y;
  3. regexp.lastIndex = 3;
  4. alert( regexp.exec(str) ); // null(位置 3 有一个空格,不是单词)
  5. regexp.lastIndex = 4;
  6. alert( regexp.exec(str) ); // varName(在位置 4 的单词)

正则表达式(RegExp)和字符串(String)的方法

str.split(regexp|substr, limit)

使用正则表达式(或子字符串)作为分隔符来分割字符串。
我们可以用 split 来分割字符串,如下所示:

  1. alert('12-34-56'.split('-')) // 数组 ['12', '34', '56']

但同样,我们也可以用正则表达式来做:

  1. alert('12, 34, 56'.split(/,\s*/)) // 数组 ['12', '34', '56']

str.replace(str|regexp, str|func)

这是用于搜索和替换的通用方法,是最有用的方法之一。它是搜索和替换字符串的瑞士军刀。
我们可以不用正则表达式来搜索和替换子字符串:

  1. // 用冒号替换连字符
  2. alert('12-34-56'.replace("-", ":")) // 12:34-56

不过有一个陷阱。
当 replace 的第一个参数是字符串时,它仅替换第一个匹配项。
您可以在上面的示例中看到:只有第一个 “-“ 被 “:” 替换了。
如要找到所有的连字符,我们不应该用字符串 “-“,而应使用带 g 标记的正则表达式 /-/g:

  1. // 将连字符替换为冒号
  2. alert( '12-34-56'.replace( /-/g, ":" ) ) // 12:34:56

regexp.test(str)

方法 regexp.test(str) 查找匹配项,然后返回 true/false 表示是否存在。

  1. let str = "I love JavaScript";
  2. // 这两个测试相同
  3. alert( /love/i.test(str) ); // true
  4. alert( str.search(/love/i) != -1 ); // true