ES6学习笔记(七)正则表达式

发布于 2021-04-18  903 次阅读


正则表达式

1、基础

1.1 含义:

通俗的来讲,正则表达式是一种匹配和替换的工具。如:在JS中验证手机号时,我们需要考虑用户输入的字符必须是number类型,且必须是11位的整数,且数字的前三位必须是134,155,183,188,199等等。对于这一问题,可以用if-else来实现,只不过太过于麻烦,而正则表达式就将这一问题简单化。

1.2 组成部分

一个完整的正则表达式由分隔符,表达式,修饰符三部分组成。
分隔符指的是除了特殊字符以外的任意字符
表达式指的是由一些特殊字符以及非特殊字符串组成
修饰符用于开启或关闭某些功能
举个例子:

let str = "1a2b3c4d5e6"
let reg = /[abcdef]/g
// 这里表示匹配abcdef这一类的字符,匹配成功就用-进行替换
console.log(str.replace(reg, '-')); // 1-2-3-4-5-6

其中,reg中的第一个/是分隔符,两个/之间的[abcef]是表达式,g是修饰符,表示全局匹配。常见的修饰符还有i表示忽略字母大小写,m表示多行搜索,搜索时识别换行符

1.3 语法

1、常见字符

字符 描述
[ABC] 匹配某类字符,如:[abc] 表示匹配某字符串中abc
^[ABC] 匹配某种字符之外的所有字符,如:[abc] 表示匹配某字符串中除abc之外的所有字符
[A-Z] 匹配所有大写字母
[a-z] 匹配所有小写字母
[\s] 匹配空白符,包括\f 换页符,\r 回车符,\t 水平制表符,\n 换行符,\x0b 垂直制表符等
[\S] 匹配非空白符
\w 匹配单词字符,包括数字,字母,下划线
\W 匹配非单词字符,除数字,字母,下划线之外的所有字符
.(点) 匹配除了回车符和换行符之外的所有字符
\d 匹配数字字符,等同于[0-9]
\D 匹配非数字字符,等同于^[0-9]

2、特殊字符和限定符

字符 描述
$ 匹配输入字符串的结尾位置
* 匹配前面的子表达式零次或多次
+ 匹配前面的子表达式一次或多次
? 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符
^ 匹配输入字符串的开始位置
( ) 标记一个子表达式的开始和结束位置
| 指明两项之间的一个选择
{n} n 是一个非负整数。匹配确定的 n 次
{n,} n 是一个非负整数。至少匹配n 次
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次

注意:+ 和 *都是贪婪的,它们会尽可能多的匹配,只有在它们的后面加上一个 ? 就可以实现非贪婪或最小匹配
举个例子:

  • do 能匹配 "d" 以及 "doo"。 等价于{0,}
  • 'do+' 能匹配 "do" 以及 "doo",但不能匹配 "d"。+ 等价于 {1,}
  • "do(es)?" 可以匹配 "do" 、 "does" 中的 "does" 。? 等价于 {0,1}
  • 'o{2}' 不能匹配 "do" 中的 'o',但是能匹配 "food" 中的两个 o
  • 'o{2,}' 不能匹配 "do" 中的 'o',但是能匹配 "food" 中的两个 o以及"foood"中的3个o
  • 'o{2,5}' 不能匹配 "do" 中的 'o',但是能匹配 "food" 中的两个 o以及"foood"中的3个o以及"fooood"中的4个o

1.4 正则表达式对象

JavaScript中使用RegExp对象来封装一个正则表达式,并提供相关的方法和属性。有两种创建方法,分别如下:

  • 字面量创建方法
let reg = /\bis\b/g;  //表示全局匹配左右的单词边界为is的所有字符
let str = "He is a boy. This is a dog. Where is she?";
// 这里的3个is左右两边都有完整的单词,都会匹配。
console.log(str.replace(reg, "IS"));  // He IS a boy. This IS a dog. Where IS she?
  • 构造函数创建方法
let reg = new RegExp("\\bis\\b", "g");
let str = "He is a boy. This is a dog. Where is she?";
console.log(str.replace(reg, "IS")); // He IS a boy. This IS a dog. Where IS she?

1.5 字符类

  • 一般情况下,正则表达式一个字符对应字符串的一个字符。
    例如:表达式 ab\t 的含义是 "ab"紧接着一个 tab(制表符)。
  • 当需要匹配一类字符时,可以使用[ ]来构造一个简单的类。
    所谓类,是指符合某些特性的对象,一个泛指,而不是特指某个字符。
    例如:表达式[abc]把字符 a、b、c 归位一类,表达式可以匹配这类字符,即匹配其中之一。如:

    let str = "a1b2c3d4"; 
    let reg = /[abc]/g // 表示全局匹配字符a,b,c
    console.log(str.replace(reg, "x")); // x1x2x3d4
  • 使用元字符\^创建反向类(负向类),即匹配不属于该类的字符。
    例如:[^abc]表示不是字符 a、b、c 其中之一的字符。如:

    let str = "a1b2c3d4"; 
    let reg = /[^abc]/g // 表示全局匹配字符a,b,c
    console.log(str.replace(reg, "x")); // axbxcxxx

1.6 范围类

  • 需要匹配数字时,可以使用范围类。
    例如:[a-z]表示从 a 到 z 之间的任意字符,且包含 a 和 z 本身。如:

    let str = "a1b2c3d4z0";
    console.log(str.replace(/[a-z]/g, "X"));  //全局匹配所有的小写字母并替换成X,输出结果 X1X2X3X4X0
  • 在[ ]中可以将一些范围连续书写

    let str = "a1b2c3D5E6F7";
    console.log(str.replace(/[a-zA-Z0-9]/g, "*")); // 全局匹配大小写字幕和数字并替换成*  输出 ************
    str = "1998-09-19";
    console.log(str.replace(/[0-9-]/g, "0")); //全局匹配数字和下换线并替换成0 输出结果 0000000000

1.7 边界

字符 描述
^ 以 xxx 开始
$ 以 xxx 结束
\b 单词边界
\B 非单词边界

举个例子:

let str = "This is a boy";
console.log(str.replace(/is/g, "0")); // 全局匹配所有的is,输出Th0 0 a boy
console.log(str.replace(/\bis\b/g, "0")); // This 0 a boy
console.log(str.replace(/\Bis\b/g, "0"));// 全局匹配左边界不是完整单词右边界是单词的字符,输出Th0 is a boy
let str = "@123@abc@";
console.log(str.replace(/@./g, "Q")); // 全局匹配@以及后面跟任意字符的字符,输出Q23Qbc@
console.log(str.replace(/^@./g, "Q")); // 全局匹配以@开头以及后面跟任意字符的字符,输出Q23@abc
console.log(str.replace(/.@/g, "Q")); // 全局匹配任意字符后跟@的字符,输出@12QabQ
console.log(str.replace(/.@$/g, "Q")); // 全局匹配任意字符后跟以@结尾的字符,输出@123@abQ
str = `@123
@456
@789`;
console.log(str.replace(/^@\d/g, "X"));
/* 这里表示全局匹配以@开头的数字字符进行替换,因此输出:
X23
@456
@789 */
console.log(str.replace(/^@\d/gm, "X"));
/* 这里表示全局匹配,多行搜索以@开头的数字字符进行替换,因此输出:
X23
X56
X89 */

1.8 分组,或,反向引用,忽略分组

  • 分组()
let str = "a1b2c3d4"
console.log(str.replace(/[a-z]\d{3}/g, "X"));  // 表示单独匹配3次小写字母和数字,输出a1b2c3d4
console.log(str.replace(/([a-z]\d){3}/g, "X"));  // 表示匹配3次小写字母和数字组成的分组,输出Xd4
  • 或 |,表示左右字符二选一
console.log("ByronCasper".replace(/Byron|Casper/g, "X")); // 全局匹配Byron或者Casper并进行替换,输出XX
console.log("ByrCasperByronsper".replace(/Byr(on|Ca)sper/g, "X")); // 全局匹配Byronsper或者ByrCasper并进行替换,输出XX
  • 反向引用:使用$n的形式引用模式中分组匹配到的文本,n为索引,从1开始,如:把 2020-03-04 替换成 03/04/2020,代码如下:
// $n 反向引用
console.log("2020-03-04".replace(/(\d{4})-(\d{2})-(\d{2})/g, "$2/$3/$1")); // 表示先全局匹配4位数字-2位数字-2位数字各分组组成的字符串,再通过索引排序,并将-替换成/ 输出03/04/2020
  • 忽略分组:当不想捕获分组时,可以使用?:直接输出$n,如:
// 忽略分组
console.log("2020-03-04".replace(/(\d{4})-(\d{2})-(?:\d{2})/g, "$2/$3/$1")); // 03/$3/2020

1.9 前瞻

  • 前瞻分为正向前瞻exp(?=assert)和负向前瞻exp(?!assert)
  • exp 和 assert 都是正则表达式,匹配到 exp 时还要判断 assert 是否符合,如果符合才会被匹配。
    例如:表达式\w(?=\d),表示匹配到一个单词\w 时还需要向后判断是否为一个数字\d
console.log("a2*34V8".replace(/\w(?=\d)/g, "X")); // X2*X4X8
console.log("a2*34V8".replace(/\w(?!\d)/g, "X")); // aX*3XVX

2、JavaScript中的正则表达式

2.1 RegExp对象属性

global,是否全文搜索,默认 false。
ignoreCase,是否忽略大小写,默认 false。
multiline,是否多行搜索,默认 false。
lastIndex,当前表达式匹配内容的最后一个字符的下一个位置。
source,正则表达式的文本字符串。
举个例子:

let reg1 = /\w/;
let reg2 = /\w/gim;
console.log(reg1.global); // false
console.log(reg1.ignoreCase); // false
console.log(reg1.multiline); // false
console.log(reg2.global); // true
console.log(reg2.ignoreCase); // true
console.log(reg2.multiline); // true
//以上三个属性都是只读的。
console.log(reg2.source); // \w

2.2 RegExp对象方法

  • test(str),用于测试字符串参数中是否存在匹配正则表达式模式的字符串,返回 true 或 false。
  • exec(str),使用正则表达式模式对字符串执行搜索,并将更新全部 RegExp 对象的属性以反映匹配结果。
    • 如果没有匹配的文本则返回 null,否则会返回一个结果“数组”对象:
      [匹配到的文本, 与第 1 个分组相匹配的文本,与第 n 个分组相匹配的文本...]
    • index,声明匹配文本的第一个字符的位置
    • input,存放被检索的字符串 string

举个例子:

let reg1 = /\w{1,2}/g; // 表示1~2位单词字符(包括数字,字母,下换线)
console.log(reg1.test("ab,cd")); // ab,cd符合reg1的规则,输出true
console.log(reg1.exec("ab,cd")); // [ 'cd', index: 3, input: 'ab,cd', groups: undefined ]
console.log(reg1.source); // \w{1,2}

2.3 字符串正则方法

  • search(reg),用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串。返回第一个匹配结果的 index,没有匹配到返回-1。不执行全局匹配。
  • match(reg),检索字符串以找到一个或多个与 regexp 匹配的文本,未找到返回 null,找到后返回一个数组。与 RegExp 的 exec()方法相同。
  • split(reg),利用 regexp 匹配结果作为分隔符对字符串进行分割,返回一个数组。
  • replace(reg, newStr),将 regexp 的匹配结果替换成 newStr,返回一个新字符串。
    举个例子:
let str = "<java> and <javascript> is deferent!";
console.log(str.match(/<\S*>/g)); // [ '<java>', '<javascript>' ]
console.log(str.replace(/<(\S*)>/g, "<<$1>>")); // <<java>> and <<javascript>> is deferent!
console.log(str.split(/[<>]/g)); // [ '', 'java', ' and ', 'javascript', ' is deferent!' ]

活的像诗一样