1. 修饰符

  • g:global 全文搜索,如果不添加,则搜索到第一个匹配时停止
  • i:ignoreCase 忽略大小写,默认大小写敏感
  • m:multiline 多行匹配

2. 元字符

正则表达式由两种基本字符类型组成:

  • 原义文本字符
  • 元字符

元字符是在正则表达式中有特殊含义的非字母字符,包含:

  • \:转义,将具有特殊意义的元字符转成原义文本字符
  • .:除了换行以外的所有字符
  • +:至少一个,一次或者多次
  • ?:至多一次,零或者一次
  • *:任意次
  • $:以 … 结尾
  • ^:字符类取反、或者以 … 开头
  • |:或
  • ():分组
  • {}:用来包裹量词范围
  • []:用来包裹字符类 | 字符 | 含义 | | —- | —- | | \t | 水平制表符 | | \v | 垂直制表符 | | \n | 换行符 | | \r | 回车符 | | \0 | 空字符 | | \f | 换页符 | | \cX | 与X对应的控制字符(Ctrl+X) |

3. 字符类

一般情况下,正则表达式一个字符对应一个字符,如 ab\t,表示字符 ‘ab’ 以及一个制表符 tab

如果我们需要匹配一类字符,可以使用元字符 [] 来构建一个简单的类。所谓的类是指符合某些特性的对象,是一个泛指。如 [abc] 把字符 a 或 b 或 c 归为一类,只要有里面的一个,就能匹配。

  1. 'a1b2c3c'.replace(/[abc]/g, 'X'); // 'X1X2X3X'

中括号中出现的元字符一般都是代表本身含义的

  1. let reg = /^[.]+$/;
  2. reg.test('.'); //=> true

中括号中的 - 有特殊含义,一般需要放在后面或者前面来代表本义
中括号中出现两位数,不是两位数,而是代表两个数中的任意一个

  1. let reg = /^[12-65]$/g //=> 表示 1 或者 2-6 或者 5

3.1 字符类取反

使用元字符 ^ 创建反向类/负向类,就是不属于某类的内容。如 [^abc] 表示不是字符 a 或 b 或 c 的内容。

  1. 'a1b2c3c'.replace(/[^abc]/g, 'X'); // 'aXbXcXc'

3.2 范围类

使用 - 来连接两个字符,如 [a-z] 表示从 a 到 z 的任意字符,这是一个闭区间,包含 a 和 z 本身。

  1. 'a1b2d3x4z9'.replace(/[a-z]/g, 'Q'); // 'Q1Q2Q3Q4Q9'

[] 组成的类内部是可以连写的,如 [a-zA-Z]

注意:横线并不是元字符,但是在上面的情况是特指范围,不会匹配到 -。如果需要匹配到横线,只需要在后面再加上横线。[a-z-] 表示 a 到 z 以及横线。

3.3 预定义类

正则表达式提供预定义类来匹配常见的字符类。

字符 等价类 含义
. [^\r\n] 除了回车符和换行符之外的所有字符
\d [0-9] 数字字符
\D [^0-9] 非数字字符
\s [\t\n\x0B\f\r] 空白字符
\S [^\t\n\x0B\f\r] 非空白字符
\w [a-zA-Z_0-9] 单词字符(字母、数字、下划线)
\W [^a-zA-Z_0-9] 非单词字符

4. 边界

正则表达式还提供了几个常用的边界匹配字符

  • ^:以……开始
  • $:以……结束
  • \b:单词边界
  • \B:非单词边界
  1. // 开头结尾匹配
  2. '@12@12@1'.replace(/@./g, '0'); // '02020'
  3. '@12@12@1'.replace(/^@./g, '0'); // '02@12@1'
  4. '@12@12@1'.replace(/@.$/g, '0'); // '@12@120'
  5. // 多行开头结尾匹配
  6. ‘@12
  7. @12
  8. @12’.replace(/^@./g, '0');
  9. // '02
  10. // @12
  11. // @12'
  12. ‘@12
  13. @12
  14. @12’.replace(/^@./gm, '0');
  15. // '02
  16. // 02
  17. // 02'
  18. // 单词边界
  19. 'This is a boy'.replace(/is/g, '0'); // 'Th0 0 a boy'
  20. 'This is a boy'.replace(/\bis\b/g, '0'); // 'This 0 a boy'
  21. 'This is a boy'.replace(/\Bis\b/g, '0'); // 'Th0 is a boy'

5. 量词

  • ?:出现零次或者一次(最多一次)
  • +:出现一次或多次(至少出现一次)
  • *:出现零次或者多次(任意次)
  • {n}:出现 n 次
  • {n,m}:出现 n 到 m 次
  • {n,}:至少出现 n 次

注意:量词只作用于紧挨它的前一个正则字符

贪婪模式:正则表达式会在范围允许内尽可能多的匹配。
非贪婪模式:让正则表达式尽可能少的匹配,一旦匹配成功就不再继续匹配。

默认正则表达式都是贪婪模式。如果需要实现非贪婪模式,只需要在量词后加上 ? 即可。

  1. // 贪婪模式
  2. '123456789'.replace(/\d{3,6}/g, 'X'); // 'X78'
  3. // 非贪婪模式
  4. '123456789'.replace(/\d{3,6}?/g, 'X'); // 'XX78'

6. 分组

如果要匹配 destiny 连续出现的场景,如果使用 destiny{3},那么只会匹配到 destinyyy,而不是 destinydestinydestiny

这时就需要使用 () 分组,使量词作用于分组。(destiny){3}

分组的作用:

  1. 提升优先级
  2. 分组匹配,可以理解成大正则里边的小正则
  3. 分组捕获
  1. let reg = /^1|8$/
  2. '1' //=> true
  3. '8' //=> true
  4. '18' //=> true
  5. //=> 以 18 开头或 19 结束
  6. let reg = /^18|19$/;
  7. '18'; //=> true
  8. '19'; //=> true
  9. '1819'; //=> true
  10. '181'; //=> true
  11. '819'; //=> true
  12. '189'; //=> true
  13. '119'; //=> true
  14. //=> 如果只是想要匹配 18 或 19
  15. let reg = /^(18|19)$/

6.1 或

使用 | 可以达到或的效果

  1. 'ByronCasper'.replace(/Byron|Casper/g, 'X'); // 'XX'
  2. 'ByronsperByrCasper'.replace(/Byr(on|Ca)sper/g, 'X'); // 'XX

6.2 分组捕获

分组后,可以使用 $1 - $n 来表示各个分组匹配到的内容。即可以把分组内的内容捕获到。

  1. '2018-05-11'.replace(/(\d{4})-(\d{2})-(\d{2})/g, '$2/$3/$1'); //=> 05/11/2018

6.3 分组引用

正则中,使用 \1\2 等,来引用正则中出现的分组捕获的内容

  1. //=> 匹配到四个字符的字母,其中第一个与最后一个一样,第二位与倒数第二位一样
  2. let reg = /^([a-Z])([a-Z])\2\1¥/;
  3. 'oppo' //=> true
  4. 'abba' //=> true

6.4 忽略分组

如果不希望捕获某些分组,只需要在分组内加上 ?:就可以,如 (?:Byron).(ok),这时,$1 就捕获 ok 分组匹配的内容

7. 前瞻

正则表达式从文本头部向尾部开始解析,称为“前”。

前瞻就是在正则表达式匹配到规则中的时候,向前检查是否符合断言,后顾方向相反。JavaScript 不支持后顾。

符合和不符合特定断言称为肯定/正向匹配否定/负向匹配

名称 正则
正向前瞻 exp(?=assert)
负向前瞻 exp(?!assert)

正向前瞻:例 \w(?=\d),在是单词的基础上向前判断后面紧跟的是否是数字,这里只匹配单词,后面括号内的只是判断单词是否符合条件。

  1. 'a2*3'.replace(/\w(?=\d)/g, 'X'); // 'X2*3'
  2. 'a2*34v8'.replace(/\w(?=\d)/g, 'X'); // 'X2*X4X8'

负向前瞻:例 \w(?!\d),在单词的基础上向前判断后面紧跟的是否不是数字,这里也是只匹配单词,后面的只是判断条件。

  1. 'a2*3'.replace(/\w(?!\d)/g, 'X'); // 'aX*3'
  2. 'a2*34v8'.replace(/\w(?!\d)/g, 'X'); // 'aX*3XvX'