你笑了

你的笑,是星星跳跃浪花的笑

0%

JS中的正则表达式

正则对象 RegExp.prototype

每次遇到 /regexp/new RegExp(regexp) 都会重新创建正则表达式对象

  • 把正则表达式保存在变量中复用则不会重新创建

JavaScript 中的正则表达式对象是有状态的,其lastIndex属性用来保存 在字符串中进行下次匹配的偏移值。

  • 每次匹配(执行 exec()test() )都会更新 lastIndex 的值

    • 匹配成功,更新到匹配文本的下一个字符位置
    • 匹配失败,更新为0
  • 更换查找的字符串,不改变正则对象的 lastIndex 属性值

  • while循环条件中使用正则表达式对象

    • 非复用正则对象,每次循环都会创建新的正则对象,lastIndex 属性值为0,如果匹配成功,将造成死循环

    • 复用正则对象,没有指定 /g 模式,如果匹配成功,lastIndex 属性重置为0,将造成死循环

      如果指定/g 模式,匹配成功将更新 lastIndex 属性值,直到字符串末尾,匹配结束,循环结束,不会造成死循环

exec

对指定字符串执行搜索匹配。返回一个结果数组或 null

语法

1
regexObj.exec(str)
  • 如果匹配成功,返回一个数组, 并更新 regexObj 对象的 lastIndex 属性值

    索引 描述
    [0] 整体匹配的文本(整个正则表达式匹配的文本)
    [1],…[n] 分组捕获的内容(如果没有分组,则没有这一项
    index 整体匹配的文本的第一个字符在原始字符串中基于0的索引值
    input 原始字符串
    groups 具名捕获时,用于存储匹配文本的对象. 默认为 undefined, 只有采用具名捕获时才有值
  • 如果匹配失败,返回 null,并将 lastIndex 重置为 0

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    const regexp2 = /([a-z]+)#([A-Z]+)#(\d{4})/;  // 复用正则表达式对象
    const str2 = 'lazada#MY#5474 amazon#VN#1234';

    // =============分组捕获==============
    console.log('exec2 = ', regexp2.exec(str2), regexp2.lastIndex);
    console.log('exec3 = ', regexp2.exec(str2), regexp2.lastIndex); // 遍历第二个
    // 输出
    exec2 = [
    'lazada#MY#5474', // 整个正则表达式匹配的文本
    'lazada', // 分组匹配的内容
    'MY', // 分组匹配的内容
    '5474', // 分组匹配的内容
    index: 0, // 整个正则表达式匹配的文本的第一个字符在原始字符串中的索引
    input: 'lazada#MY#5474 amazon#VN#1234', // 原始字符串
    groups: undefined
    ] 0
    exec3 = [ // 未加 g 标志时, 多次执行的结果相同
    'lazada#MY#5474',
    'lazada',
    'MY',
    '5474',
    index: 0,
    input: 'lazada#MY#5474 amazon#VN#1234',
    groups: undefined
    ] 0

    // =============未分组捕获==============
    > /[^a-c]+/.exec('bike');
    [ 'ike', index: 1, input: 'bike', groups: undefined ]
  • 如果使用g标志,匹配成功后,会更新 lastIndex 属性。使用此特性,可多次执行 exec 方法来查找同一个字符串中的多个匹配项

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    exec2 =  [
    'lazada#MY#5474',
    'lazada',
    'MY',
    '5474',
    index: 0,
    input: 'lazada#MY#5474 amazon#VN#1234',
    groups: undefined
    ] 14 // 记录 lastIndex
    exec3 = [ // 多次执行,结果不同
    'amazon#VN#1234',
    'amazon',
    'VN',
    '1234',
    index: 15,
    input: 'lazada#MY#5474 amazon#VN#1234',
    groups: undefined
    ] 29

test

  • 检测指定字符串是否匹配正则表达式

语法

1
regexObj.test(str)
  • 返回值

    • 类型:布尔

    • true

      字符串与正则表达式匹配

    • false

      不匹配

  • 通过RegExp.$1~RegExp.$9:获取本次正则匹配后,第一个到第九个分组的信息(不常用)

    没有 RegExp.$0

1
2
3
4
5
6
7
8
9
10
11
12
13
let str = "{0}年{1}月{2}日";
let reg = /\{(\d+)\}/g;
console.log(reg.test(str)); //=>true
console.log(RegExp.$1); //=>"0"

console.log(reg.test(str)); //=>true
console.log(RegExp.$1); //=>"1"

console.log(reg.test(str)); //=>true
console.log(RegExp.$1); //=>"2"

console.log(reg.test(str)); //=>false
console.log(RegExp.$1); //=>"2" 存储的是上次捕获的结果

字符串 String.prototype

  • 检测字符串是否匹配正则表达式

  • 寻找正则表达式在字符串中第一次匹配成功的位置。如果匹配失败,则返回-1

    全局模式/g 不影响返回结果

语法

1
str.search(regexp)
  • 返回值

    • 类型:Number

    • 匹配成功则返回首次匹配文本的索引

      索引从0开始,匹配文本的第一个字符的索引

    • 匹配失败则返回 -1

replace

  • 替换字符串中的指定部分,返回一个新字符串(不改变原字符串
  • 默认只进行一次替换

语法

1
str.replace(regexp|substr, replacement|function)
  • regexp

    一个 RegExp 对象或者其字面量。该正则所匹配的内容会被第二个参数替换掉

  • substr

    字符串,指定原字符串中被替换的部分

    1. 仅第一个匹配项会被替换
    2. 每次匹配都从字符串第一个字符开始
  • replacement

    替换字符串,用于替换第一个参数在原字符串中匹配到的结果

    替换字符串中可以使用的特殊变量名

    变量名 描述
    $$ 插入一个’$’字符
    $& 插入匹配的子串
    $` 插入当前匹配子串左侧的所有字符
    $’(英文单引号) 插入当前匹配子串右侧的所有字符
    $n 插入对应捕获分组匹配的子串,索引从1开始,如果没有对应的分组,则替换为字面量( ‘$3’)
    $<name> 插入命名分组捕获的子串,如果不存在命名分组则替换为字面量,如果存在但引用名称错误则替换为空串
    1
    2
    3
    4
    5
    6
    7
    > 'the price is 12.99 dollar'.replace(/(\d+\.\d{0,2})/u,"$$ $0 $1 $`$' $& $<age>");
    'the price is $ $0 12.99 the price is dollar 12.99 $<age> dollar'
    >
    > 'the price is 12.99 dollar'.replace(/(?<num>\d+\.\d{0,2})/u,"$$ $0 $1 $`$' $& $<num>");
    'the price is $ $0 12.99 the price is dollar 12.99 12.99 dollar'
    > 'the price is 12.99 dollar'.replace(/(?<num>\d+\.\d{0,2})/u,"$$ $0 $1 $`$' $& $<num> $<sum>");
    'the price is $ $0 12.99 the price is dollar 12.99 12.99 dollar' #替换为空串
  • function

    回调函数,返回一个字符串,替换第一个参数匹配到的子串

    1. 用正则reg跟字符串str进行匹配,获取匹配内容(字符串数组,跟 exec 捕获的结果一致)

    2. 执行回调函数,并把捕获到的内容以字符串列表的形式传递给回调函数

      参数名 描述
      match 整个正则匹配的结果
      p1,p2…pn 分组捕获的结果
      offset 整个正则匹配的结果的第一个字符在原字符串中的索引
      string 原字符串
      1
      2
      3
      4
      5
      6
      7
      8
      9
      function replacer(match, p1, p2, p3, offset, string) {
      console.log(match, p1, p2, p3, offset, string);
      // c12345#$*% c 12345 #$*% 3 ab6c12345#$*%111
      return [p3, p2, p1].join('-');
      }
      // 整个正则作为一个整体去匹配,而不是每个组单独匹配。
      // 做为一个整体匹配后,再分组捕获
      var newString = 'ab6c12345#$*%111'.replace(/([^\d]*)(\d*)([^\w]+)/, replacer);
      console.log(newString); // ab6#$*%-12345-c111
    3. 用回调函数的返回结果替换第一个参数匹配到的结果

      每匹配一项,上面的3步就执行一次。替换之后再去匹配下一项

      功能强大,真实项目中推荐使用

示例

第一个参数为字符串

  • 每次匹配都从字符串第一个字符开始,且只能替换一个匹配项(类似正则的懒惰性)

    基于正则 g 修饰符解决replace的“懒惰性”

    1
    2
    3
    4
    5
    6
    7
    8
    let str = "zhufeng@2019|zhufeng@2020";
    //=>把"zhufeng"替换成"珠峰"
    str = str.replace("zhufeng","珠峰").replace("zhufeng","珠峰");
    console.log(str);

    //2.使用正则会简单一点
    str = str.replace(/zhufeng/g,"珠峰");
    console.log(str);

第一个参数为正则

  • 处理时间字符串

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    let time = "2019-08-13";
    //=>变为"2019年08月13日"

    let reg = /^(\d{4})-(\d{1,2})-(\d{1,2})$/;

    //方式一:通过 $1~9 获取小分组匹配捕获到的内容
    time = time.replace(reg,"$1年$2月$3日");
    console.log(time); //=>2019年08月13日

    // 方式二:底层原理
    time = time.replace(reg, (big, $1, $2, $3) => {
    //=>这里的$1~$3是我们自己设置的变量
    console.log(big, $1, $2, $3);
    });

    time = time.replace(reg, (...args) => {
    // 不接收第一项大正则捕获的内容,空出来(用逗号隔开)
    // 解构赋值
    let [, $1, $2, $3] = args
    $2.length < 2 ? $2 = "0" + $2 : null;
    $3.length < 2 ? $3 = "0" + $3 : null;
    return $1 + "年" + $2 + "月" + $3 + "日";
    })
  • 单词首字母大写

    • 大正则捕获每个单词
    • 小分组捕获单词的首字母
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    let str = "good good study,day day up!"
    // 要获取首字母,则第一个小正则用小括号包起来
    let reg = /\b([a-zA-Z])[a-zA-Z]*\b/g;
    //=>函数被执行了六次,每一次都把正则匹配信息传递给函数,arg:["good","g"] ["good","g"] ["study","s"]...
    str = str.replace(reg, (...arg) => {
    let [content, $1] = arg;
    // 首字母大写
    $1 = $1.toUpperCase();
    // 获取单词除首字母之外的字符串
    content = content.substring(1);
    // 返回拼接后的字符串
    return $1 + content;
    });
    console.log(str); //=>"Good Good Study,Day Day Up!"

match

  • 捕获与正则表达式匹配的结果,返回一个结果数组或 null

语法

1
str.match(regexp)
  • 正则表达式/g模式

    返回一个字符串数组,包含与大正则(整个正则表达式)匹配的结果,但不包含分组捕获的结果

  • 正则表达式不加 /g 模式

    返回与大正则(整个正则表达式)匹配的结果,及分组捕获的结果,及相关属性

    属性 描述
    [0] 大正则(完整正则表达式)匹配的结果
    [1],[2],…[n] 分组捕获的结果
    index 大正则(完整正则表达式)匹配结果的第一个字符的索引
    input 原字符串
    groups 一个捕获组数组 或 undefined(未定义命名捕获组)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    > '#ax'.match(/#(?<site>[A-Z]*)/)
    [
    '#',
    '',
    index: 0,
    input: '#ax',
    groups: [Object: null prototype] { site: '' }
    ]
    > '#ax'.match(/#(?<site>[A-Z]*)/).groups.site
    ''
    >
    > '#ax'.match(/#([A-Z]*)/)
    [ '#', '', index: 0, input: '#ax', groups: undefined ]
    > '#ax'.match(/#([A-Z]*)/).groups.site
    Uncaught TypeError: Cannot read property 'site' of undefined
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    var str = 'hi see Chapter 3.4.5.1';
    var re = /see (chapter \d+(\.\d)*)/i;
    var found = str.match(re);

    console.log(found);

    // [
    // 'see Chapter 3.4.5.1',
    // 'Chapter 3.4.5.1',
    // '.1', // 捕获了3次,在保存最后一次的结果
    // index: 3,
    // input: 'hi see Chapter 3.4.5.1',
    // groups: undefined
    // ]


    var re = /see (chapter \d+(\.\d)*)/gi;
    var found = str.match(re);

    console.log(found);
    // [ 'see Chapter 3.4.5.1' ]

split

使用指定的分隔符分割字符串,返回一个字符串数组

语法

1
str.split(separator [, limit])
  • separator 可以是正则表达式

    如果正则表达式包含捕获分组,则捕获文本会被拼接到返回数组中

    1
    2
    3
    4
    5
    > 'one1two2three'.split(/\d/u,3)
    [ 'one', 'two', 'three' ]
    >
    > 'one1two2three'.split(/(\d)/u,3)
    [ 'one', '1', 'two' ]