[Javascript] 正则表达式匹配的常用方法总结

正则

  • 正则表达式是用于匹配字符串中字符组合的模式。在 JavaScript中,正则表达式也是对象。这些模式被用于 RegExp 的 exec 和 test 方法, 以及 String 的 match、matchAll、replace、search 和 split 方法。

  • 正则表达式对象常用属性

属性作用
lastIndex下一次匹配开始的位置
  • 通过标志进行高级搜索
标志描述
g全局搜索。
i不区分大小写搜索。
m多行搜索。
s允许 . 匹配换行符。
u使用unicode码的模式进行匹配。
y执行“粘性(sticky)”搜索,匹配从目标字符串的当前位置开始。

正则表达式对象的lastIndex属性的作用是什么

举一个使用了RegExp.test()方法的例子

  • RegExp.prototype.test()方法用于检测一个字符串是否匹配某个模式。如果字符串中有匹配的值返回 true ,否则返回 false。
var regexp = /abcd/g;
var str = 'abcdefg';
console.log(regexp.lastIndex,regexp.test(str),regexp.lastIndex);  // 0 true 4
console.log(regexp.lastIndex,regexp.test(str),regexp.lastIndex);  // 4 false 0
console.log(regexp.lastIndex,regexp.test(str),regexp.lastIndex);  // 0 true 4

console.log(regexp.lastIndex,regexp.test("habcde"),regexp.lastIndex);  // 4 false 0
  • lastIndex指示正则表达式开始下一次查找的索引位置,第一次的时候总是为0的,第一次查找完了的时候会把lastIndex的值设为匹配到得字符串的最后一个字符的索引位置加1,第二次查找的时候会从lastIndex这个位置开始,后面的以此类推。如果没有找到,则会把lastIndex重置为0。要注意的是,lastIndex属性只有在有全局标志正则表达式中才有作用,如果我们把上面代码中正则表达式的g标志去掉,那么三次弹出的就都是true了。
var regexp = /abcd/;
var str = 'abcdefg';
console.log(regexp.lastIndex,regexp.test(str),regexp.lastIndex);  // 0 true 0
console.log(regexp.lastIndex,regexp.test(str),regexp.lastIndex);  // 0 true 0
console.log(regexp.lastIndex,regexp.test(str),regexp.lastIndex);  // 0 true 0

console.log(regexp.lastIndex,regexp.test("habcde"),regexp.lastIndex); // 0 true 0

再举一个使用例子RegExp.exec()的例子

  • RegExp.prototype.exec() 方法用于检索字符串中的正则表达式的匹配。如果字符串中有匹配的值返回该匹配值,否则返回 null。(后面详细介绍改方法的使用)
var re2 = /\d/g;
console.log(re2.exec("123 456"), re2.lastIndex); 
// ["1", index: 0, input: "123 456", groups: undefined]  1

console.log(re2.exec("123 456"), re2.lastIndex); 
// ["2", index: 1, input: "123 456", groups: undefined]  2

console.log(re2.exec("123 456"), re2.lastIndex); 
// ["3", index: 2, input: "123 456", groups: undefined]  3

console.log(re2.exec("123 456"), re2.lastIndex); 
// ["4", index: 4, input: "123 456", groups: undefined]  5

console.log(re2.exec("123 456"), re2.lastIndex);
// ["5", index: 5, input: "123 456", groups: undefined]  6

console.log(re2.exec("123 456"), re2.lastIndex);
// ["6", index: 6, input: "123 456", groups: undefined]  7

console.log(re2.exec("123 456"), re2.lastIndex);
// null re2.lastIndex:0"

console.log(re2.exec("123 456"), re2.lastIndex);
// ["1", index: 0, input: "123 456", groups: undefined]  1
  • 和上面test的例子一样,可以看出在使用了g标志时,lastIndex属性很重要。

什么是捕获组

正则表达式的子表达式(捕获组):子表达式是一个更大的表达式的一部分,子表达式通过()括起来,这个括号成为捕获括号。

一个正则表达式模式使用括号,将导致相应的子匹配被记住。例如,/a(b)c /可以匹配字符串“abc”,并且记得“b”。

除了捕获括号还有非捕获括号。非捕获括号就无法记住子匹配项,只有分组的作用

描述
(x)它会匹配 ‘x’ 并且记住匹配项。其中括号被称为捕获括号
模式 /(foo) (bar) \1 \2/ 中的 ‘(foo)’ 和 ‘(bar)’ 匹配并记住字符串 “foo bar foo bar” 中前两个单词。模式中的 \1 和 \2 表示第一个和第二个被捕获括号匹配的子字符串,即 foo 和 bar,匹配了原字符串中的后两个单词。
(foo)和(bar)就是捕获组。
注意 \1、\2、…、\n 是用在正则表达式的匹配环节。而在正则表达式的替换环节,则要使用像 $1、 2 、 . . . 、 2、...、 2...n 这样的语法,例如,‘bar foo’.replace(/(…) (…)/, '$2 1 ′ ) 。 1')。 1)& 表示整个用于匹配的原字符串。
(?:x)匹配 ‘x’ 但是不记住匹配项。这种括号叫作非捕获括号,使得你能够定义与正则表达式运算符一起使用的子表达式。看看这个例子 /(?:foo){1,2}/。如果表达式是 /foo{1,2}/,{1,2} 将只应用于 ‘foo’ 的最后一个字符 ‘o’。如果使用非捕获括号,则 {1,2} 会应用于整个 ‘foo’ 单词。

sticky 标志和 global 标志的不同点

  • sticky标识代表下一个匹配的位置必须在lastIndex处,global标识表示下一次匹配的位置可以在lastIndex及往后的位置上。
re = /\d/y;
while (r = re.exec("123 456")) console.log(r, "AND re.lastIndex is "+re.lastIndex);
/*
  上面的结果:
  ["1", index: 0, input: "123 456", groups: undefined] "AND re.lastIndex is 1 "
  ["2", index: 1, input: "123 456", groups: undefined] "AND re.lastIndex is 2 "
  ["3", index: 2, input: "123 456", groups: undefined] "AND re.lastIndex is 3 "
*/

re2 = /\d/g;
while (r2 = re2.exec("123 456")) console.log(r2, "AND re2.lastIndex is "+re2.lastIndex);
/*
  上面的结果:
  ["1", index: 0, input: "123 456", groups: undefined] "AND re2.lastIndex is 1 "
  ["2", index: 1, input: "123 456", groups: undefined] "AND re2.lastIndex is 2 "
  ["3", index: 2, input: "123 456", groups: undefined] "AND re2.lastIndex is 3 "
  ["4", index: 4, input: "123 456", groups: undefined] "AND re2.lastIndex is 5 "
  ["5", index: 5, input: "123 456", groups: undefined] "AND re2.lastIndex is 6 "
  ["6", index: 6, input: "123 456", groups: undefined] "AND re2.lastIndex is 7 "
*/

RegExp.prototype.test()的使用方法

前面已经举过例子拉

RegExp.prototype.exec()的使用方法

  • exec()方法在一个指定字符串中执行一个搜索匹配。返回一个结果数组或 null。
  • 在设置了 global 或 sticky标志位的情况下(如 /foo/g or /foo/y),JavaScript RegExp对象是有状态的,他们会将上次成功匹配后的位置记录在 lastIndex属性中。使用此特性,exec() 可用来对单个字符串中的多次匹配结果进行逐条的遍历(包括捕获到的匹配),而相比之下, String.prototype.match()只会返回匹配到的结果。
  • 如果匹配成功,exec() 方法返回一个数组(包含额外的属性 index 和 input等),并更新正则表达式对象的 lastIndex属性。完全匹配成功的文本将作为返回数组的第一项,从第二项起,后续每项都对应正则表达式内捕获括号(正则子项)里匹配成功的文本。
  • 如果匹配失败,exec() 方法返回 null,并将 lastIndex重置为 0 。
re2 = /a(b)(c)/g; // 全局匹配
while (r2 = re2.exec("abcabcaaacbabcd")) {
  console.log(r2, re2.lastIndex);
}
/*
  上面的结果:注意:re2.exec("123 456") 返回的是一个数组
  数组的第一项是匹配到结果,后面几项是匹配到的捕获组,
  除此之外数组身上附带了一些属性,包括index(匹配到的起始位置),input等
  ["abc", "b", "c", index: 0, input: "abcabcaaacbabc", groups: undefined] 3
  ["abc", "b", "c", index: 3, input: "abcabcaaacbabc", groups: undefined] 6
  ["abc", "b", "c", index: 11, input: "abcabcaaacbabc", groups: undefined] 14
*/
var re2 = /\d/; // 没有g标志
var re2 = /\d/;
console.log(re2.exec("123 456"), re2.lastIndex); 
// ["1", index: 0, input: "123 456", groups: undefined] 0

console.log(re2.exec("123 456"), re2.lastIndex); 
// ["1", index: 0, input: "123 456", groups: undefined] 0

console.log(re2.exec("123 456"), re2.lastIndex); 
// ["1", index: 0, input: "123 456", groups: undefined] 0

// 因为没有开启g标志,所以lastIndex属性没起作用,每次执行都是从第0个字符开始执行一次匹配
// \1表示重复正则第一个圆括号内匹配到的内容 \n表示第n个
var re = /(\w+)(\d+)\s\1/;
/*
    \w 字符类 匹配一个单字字符(字母、数字或者下划线)
    + 量词 匹配前一个表达式 0 次或多次
    \s 字符类 匹配一个空白字符,包括空格、制表符、换页符和换行符。
    \1 要和正则表达式集合()一起使用 \1表示重复正则第一个圆括号内匹配到的内容
*/
console.log(re.exec("John1 John"), re.lastIndex);
// ["John1 John", "John", "1", index: 0, input: "John1 John", groups: undefined] 0

console.log(re.exec("John1 Smith1"), re.lastIndex);
// null 0

String.prototype.match()的使用方法

  • str.match(regexp)方法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。这个方法的行为在很大程度上有赖于 regexp 是否具有标志 g。

  • 如果你没有给出任何参数并直接使用match() 方法 ,你将会得到一 个包含空字符串的 Array:[“”]

  • 如果 regexp 没有标志 g,那么 match() 方法就只能在 stringObject 中执行一次匹配,返回第一个完整匹配及其相关的捕获组。

    如果没有找到任何匹配的文本, match() 将返回 null。
    否则,它将返回一个数组,其中存放了与它找到的匹配文本有关的信息。
    该数组的第 0 个元素存放的是匹配文本,而其余的元素存放的是与正则表达式的子表达式匹配的文本。
    除了这些常规的数组元素之外,返回的数组还含有两个对象属性。
    实际上,如果正则表达式不包含 g 标志,str.match() 将返回与 RegExp.exec()相同的结果。
    index 属性声明的是匹配文本的起始字符在 stringObject 中的位置,input 属性声明的是对 stringObject 的引用。

  • 如果 regexp 具有标志 g,则 match() 方法将执行全局检索,找到 stringObject 中的所有匹配子字符串,但不会返回捕获组。

    若没有找到任何匹配的子串,则返回 null。如果找到了一个或多个匹配子串,则返回一个数组。

  • 下面看例子

var str = 'For more information, see Chapter 3.4.5.1 or seeChapter 3.4.2.1';
var re = /see (chapter \d+(\.\d)*)/i; // 没有使用g标志 有两个捕获括号
var found = str.match(re);
console.log(found);

/*
  ["see Chapter 3.4.5.1", 
  "Chapter 3.4.5.1", 
  ".1", 
  index: 22, 
  input: "For more information, see Chapter 3.4.5.1 or seeChapter 3.4.2.1", 
  groups: undefined]
*/

// 'see Chapter 3.4.5.1' 是整个匹配。
// 'Chapter 3.4.5.1' 被'(chapter \d+(\.\d)*)'捕获。
// '.1' 是被'(\.\d)'捕获的最后一个值。
// 'index' 属性(22) 是整个匹配从零开始的索引。
// 'input' 属性是被解析的原始字符串。
var str = 'For more information, see Chapter 3.4.5.1, see Chapter 3.4.2.1';
var re = /see (chapter \d+(\.\d)*)/ig; // 使用了g标志
var found = str.match(re);

console.log(found); // ["see Chapter 3.4.5.1", "see Chapter 3.4.2.1"]
// 解析url中的参数

function GetQueryValue1(str, queryName) {
    var reg = new RegExp("(^|&)" + queryName + "=([^&]*)(&|$)", "i"); 
    /*
      reg= /(^|&)name=([^&]*)(&|$)/  
      有三个捕获组,第二个捕获组([^&]*)中的是我们想要获取的信息
    */
    var r = str.match(reg);
    console.log(r);
    // ["name=小明&", "", "小明", "&", index: 0, input: "name=小明&age=12", groups: undefined]
    // ["&age=12", "&", "12", "", index: 7, input: "name=小明&age=12", groups: undefined]
    if ( r != null ){
      return decodeURI(r[2]);
    }else{
      return null;
    }
}
var queryVal=GetQueryValue1("name=小明&age=12", 'name');
console.log(queryVal); // 小明
var queryVal=GetQueryValue1("name=小明&age=12", 'age');
console.log(queryVal); // 12

String.prototype.search()的使用方法

search() 方法用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串。如果没有找到任何匹配的子串,则返回 -1。

var str="Mr. Blue has a blue house";
console.log(str.search("blue")); // 15
var str="Mr. Blue has a blue house";
console.log(str.search(/blue/i)); // 4
var str="Mr. Blue has a blue house";
console.log(str.search(/blue/ig)); // 4
// 对于search方法来说,检索的正则表达式是否开启g都一样,都返回第一个找到的位置的下标

String.prototype.replace()的使用方法

  • 语法:str.replace(regexp|substr, newSubStr|function)
  • replace() 方法返回一个由替换值替换部分或所有的模式(pattern)匹配项后的新字符串。第一个参数可以是一个字符串或者一个正则表达式,第二个参数替换值可以是一个字符串或者一个每次匹配都要调用的回调函数
  • 如果第一个参数是字符串,则仅替换第一个匹配项。
  • 原字符串不会改变,而只是返回一个新的替换后的字符串。
  • 第一个参数指定为正则表达式时,如果是全局匹配,那么会替换掉所有匹配的地方,如果没有g标志,只会匹配到第一个地方。

考虑第一个参数是正则表达式时,第二个参数的不同情况

  • 使用字符串作为替换值

    替换字符串中可以插入是一些特殊变量名

    var re = /(\w+)\s(\w+)/;
    var str = "John Smith";
    var newstr = str.replace(re, "$2, $1");
    console.log(newstr); // Smith, John
    

    上面的例子中replace的第二个参数,也就是替换值是一个字符串,并且字符串中有特殊的变量,$1表示的是第一个捕获括号匹配到的值(John),$2表示的是第二个捕获括号匹配到的值(Smith)。

  • 指定一个函数作为替换值

    • 你可以指定一个函数作为第二个参数。在这种情况下,当匹配执行后,该函数就会执行。 函数的返回值作为替换字符串。
      另外要注意的是,如果第一个参数是正则表达式,并且其为全局匹配模式,那么这个方法将被多次调用,每次匹配都会被调用。

      下面是该函数的参数:具体有多少参数是不确定的

      变量名代表的值
      match匹配的子串。
      p1,p2, …假如replace()方法的第一个参数是一个RegExp对象,则代表第n个括号匹配的字符串。(对应于上一种方案的$1,$2等。)例如,如果是用 /(\a+)(\b+)/ 这个来匹配,p1 就是匹配的 \a+,p2 就是匹配的 \b+。
      offset匹配到的子字符串在原字符串中的偏移量。(比如,如果原字符串是 ‘abcd’,匹配到的子字符串是 ‘bc’,那么这个参数将会是 1)
      string被匹配的原字符串。
      NamedCaptureGroup命名捕获组匹配的对象
      function replacer(match, p1, p2, p3, offset, string) {
          console.log(match,p1,p2,p3,offset,string);
          // abc12345#$*% abc 12345 #$*% 0 abc12345#$*%
      
          return [p1, p2, p3].join(" - ");
      }
      var newString = "abc12345#$*%".replace(/([^\d]*)(\d*)([^\w]*)/, replacer);
      console.log(newString); // abc - 12345 - #$*%
      

正则的特殊字符

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions

正则的贪婪模式

量词

*匹配前一个表达式 0 次或多次。等价于 {0,}。
+匹配前面一个表达式 1 次或者多次。等价于 {1,}。
?匹配前面一个表达式 0 次或者 1 次。等价于 {0,1}。

贪婪模式

如果**?紧跟在任何量词 * + ? 或 {} 的后面**,将会使量词变为非贪婪(匹配尽量少的字符),和缺省使用的贪婪模式(匹配尽可能多的字符)正好相反。例如,对 “123abc” 使用 /\d+/ 将会匹配 “123”,而使用 /\d+?/ 则只会匹配到 “1”。

var re = /\d+/ig;
var result = re.exec('123abc');
console.log(result); // ["123"]

var re2 = /\d+?/ig;
var result2 = re2.exec('123abc');
console.log(result2); // ["1"]

参考

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/RegExp

  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值