Fork me on GitHub

RegExp 笔记

正则表达式的概念

  • 正则表达式(regular expression)描述了一种字符串匹配的模式。这种模式,我们可以理解成是一种“规则”。根据这种规则再去匹配符合条件的结果,而匹配的过程就是检索,查找、提取的过程
  • 正则表达式只能对字符串进行操作
  • 基于不同平台或者是语言的 regular expression 并不相同,以下说的都是基于JavaScript语言的正则表达式,在JS中表现为RegExp对象。

RegExp 对象

RegExp 对象

  • RegExp是JavaScript中内置的正则对象,通过以下方法均可以创建一个正则对象的实例。
构造函数
  • var pattern = new RegExp(‘regexp’,’modifier’);
  • regexp : 匹配的模式,也就是上文指的正则规则,实际上我们编写正则表达式的过程,都是对“规则”的定义过程。
  • modifier : 正则实例的修饰符。
    1
    2
    var pattern = new RegExp('world','i');
    var reg = new RegExp('name','gi');
字面量
  • var pattern = /regexp/modifier;
  • regexp : 匹配的模式,也就是上文指的正则规则,实际上我们编写正则表达式的过程,都是对“规则”的定义过程。
  • modifier : 正则实例的修饰符。
    1
    2
    var pattern = /world/i;
    var reg = /name/gi;
说明
字面量与构造函数的区别:
字面量更类似于定义一个变量,采用赋值的方式。这种方式创建正则实例是推荐使用的方式。
注意:字面量方式下正则实例创建的格式,即用一对斜杠(//)来包裹定义的规则,规则不能用定界符括起来,随后在附加上修饰符。

修饰符说明

  • “修饰符” 其含义类似于正则实例的附加属性。用于说明正则规则适用匹配的范围。
    • i : 表示区分大小写字母匹配。
    • m :表示多行匹配。
    • g : 表示全局匹配。
      • 非全局的情况下,正则会根据指定的“规则”从左至右对字符串进行匹配,一旦规则匹配完,便会停止匹配操作,返回结果。
      • 全局的的情况下,正则会根据指定的“规则”从左至右对字符串进行匹配,一旦规则匹配完,便会在当前字符串匹配位置重新使用“规则”继续向下匹配,一直到字符串匹配完成。这也是下文中,我们会提到lastIndex属性存在的必要性

RegExp对象方法

  • RegExp对象具有内置方法,这些方法可以根据指定的规则来对字符串进行匹配,查找等。
  • 可以支持正则表达式的方法,不仅仅只有RegExp对象才有,实际上String对象也具有同样功能的方法。
test()
  • test 方法用于测试正则规则在指定的字符串中是否具有符合的匹配结果,如果匹配到则返回true,否则返回false。

    1
    2
    var pattern = /a/;
    console.log(pattern.test('edcba')) // => true
  • 当test方法在全局模式下被多次执行的时候,每次执行的返回值会因为匹配结果的不同而不同。

  • 如果多次重复执行test方法,则会根据lastIndex属性的值为锚点依次向后匹配,在匹配到字符串的末尾后,会从头到尾再重新循环匹配。
    1
    2
    3
    4
    var pattern = /a/g;
    console.log(pattern.test('edcba')) // => true 第一次执行。
    console.log(pattern.test('edcba')) // => false 第二次执行。
    console.log(pattern.test('edcba')) // => true 第三次执行。从头到尾重新循环执行。
exec()
  • 非全局的匹配模式下,此函数的作用和match()函数是一样的,只能够在字符串中匹配一次,一旦匹配到符合规则的结果,便会停止执行。
    • 在非全局匹配模式下,IE浏览器还会具有lastIndex属性,不过这时是只读的。
  • 全局模式下,当匹配到符合规则的结果也会停止执行。lastIndex属性可以设置。

    • 不过此时,此函数一般会和lastIndex属性匹配使用,此函数会在lastIndex属性指定的字符处开始检索字符串,当exec()找到与表达式相匹配的字符串时,在匹配后,它将lastIndex 属性设置为匹配字符串的最后一个字符的下一个位置
    • 可以通过反复调用exec()函数遍历字符串中的所有匹配,当exec()函数再也找不到匹配的文本时,它将返回null,并把lastIndex 属性重置为0。
    • 如果在一个字符串中完成了一次模式匹配之后要开始检索新的字符串,就必须手动地把lastIndex属性重置为0。
    1
    2
    var pattern = /a/;
    console.log(pattern.test('edcba')) // => true
  • exec方法在匹配到的情况下,返回值是一个数组(但是此数组的内容正则对象是否是全局匹配有着很大关系),同时此数组还包括两个对象属性:

    1
    2
    3
    4
    var result = /a/.exec('abcdaefga');
    result[0] // -> 当前匹配到的结果。
    result.input // -> 进行匹配操作的字符串。
    result.index // -> 当前匹配结果首字母在字符串中的索引
  • 如果正则表达式没有匹配到结果,那么返回的值就是 null

  • 如果存在分组匹配的情况下:
    result[1] -> 表示第一个分组匹配到的结果。
    result[2] -> 表示第二个分组匹配到的结果。

    result[n] -> 表示第n个分组匹配到的结果。

    1
    2
    3
    4
    5
    6
    var str = '2012 google';
    var pattern = /(\d{4})\s(\w+)/;//第一个分组(\d{4}),第二个分组(\w+)
    var result = pattern.exec(str);
    console.log(result[0]);//2012 google
    console.log(result[1]);//2012
    console.log(result[2]);//google
  • 如果想使用exec方法对字符串中的某个结果进行全面匹配(反复调用exec方法遍历字符串中的所有匹配),那么正则表达式必须要开启全局模式

  • 非全局的模式下,exec方法一旦匹配到结果便会停止执行

    1
    2
    3
    4
    var pattern = /a/g;
    while(result = pattern.exec('abababab')){
    console.log(result+' index:'+ result.index +' input:'+ result.input);
    }
    1
    2
    3
    var str="I love antzone ,this is animate"; 
    var reg=/an/;
    console.log(reg.exec(str));//["an",index:7, input:"I love antzone ,this is animate"]
  • 全局模式下可以使用lastIndex属性设置在字符串中查找指定字符时开始的位置

    1
    2
    3
    4
    var str="the name 123 and 456"; 
    var reg=/\d/g;
    reg.lastIndex=15;
    console.log(reg.exec(str));//["4",index:17, input:"the name 123 and 456"]
compile()
  • compile可以重新指定正则实例的规则与修饰符。
    1
    2
    var pattern = /res/i;
    pattern.compile('rp','g') //-> /rp/g

RegExp对象的属性

input
  • 返回当前要匹配的字符串。
  • 静态属性,调用格式:RegExp.attribute。
  • 静态属性是RegExp这个内置对象的固有属性。访问这些静态属性,不需要进行声明实例化,而是直接调用。       
    1
    2
    3
    4
    var desc = 'Hello,everyone.My name is gtshen';
    reg = /na(.?)/g;
    reg.test(desc);
    console.log('input: '+RegExp.input) // -> 'Hello,everyone.My name is gtshen'
lastMatch
  • 最后一次匹配到的子串结果,需要开启修饰符-g。
  • 静态属性,调用格式:RegExp.attribute。       
    1
    2
    3
    4
    var desc = 'Hello,everyone.My name is gtshen';
    reg = /na(.?)/g;
    reg.test(desc);
    console.log('lastMatch:'+RegExp.lastMatch) // -> nam
leftContext
  • 以当前匹配到的子串为上下文,返回之前的子串。
  • 静态属性,调用格式:RegExp.attribute。       
    1
    2
    3
    4
    var desc = 'Hello,everyone.My name is gtshen';
    reg = /na(.?)/g;
    reg.test(desc);
    console.log('leftContext:'+RegExp.leftContext) // -> 'Hello,everyone.My ';
rightContext
  • 以当前匹配到的子串为上下文,返回之后的子串。
  • 静态属性,调用格式:RegExp.attribute。       
    1
    2
    3
    4
    var desc = 'Hello,everyone.My name is gtshen';
    reg = /na(.?)/g;
    reg.test(desc);
    console.log('rightContext:'+RegExp.rightContext) // -> 'e is gtshen';
lastIndex
  • 返回当前匹配结果下一次匹配的起始位置。也可以手动设置lastIndex的值,用于设置指定的起始位置
  • 实例属性:指必须经过声明或实例化后正则表达式对象方能调用的属性。
    1
    2
    3
    4
    5
    6
    7
    var pattern = /\w?/g;
    var desc = 'hello,hi,oh';
    pattern.test(desc)
    console.log(pattern.lastIndex) //-> 1;
    pattern.lastIndex = 2;
    pattern.test(desc)
    console.log(pattern.lastIndex) // -> 3;

支持正则的String方法

  • 除了RegExp对象具有支持正则表达式的方法外,字符串String对象也具有可以支持正则表达式作为参数进行匹配筛选的的方法。
replace()
  • 该方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。
  • 格式:str.replace(regexp/substr,replacement)。
  • 返回一个新的字符串,是用 replacement 替换了 regexp 的第一次匹配或所有匹配之后得到的。
  • replace方法只会返回原字符被操作后的副本,并不会对原字符串进行改动。
    1
    2
    3
    var str = 'i see you See you';
    var pattern = /you/;
    str.replace(pattern,'*'); // -> i see * See you
match()
  • 在字符串内检索指定的值,找到一个或多个正则表达式的匹配。
  • 格式:str.match(pattern)。
  • match 在功能上与正则对象自带的方法exec很类似。
  • match 根据匹配规则pattern匹配指定的字符串str,如果匹配成功则返回一个数组格式的结果用于存放匹配文本有关的信息,如果没有匹配到则返回null。
  • 返回匹配结果的数组,数组内容依赖于regexp是否具有全局标志g

    • 如果match的匹配规则是一个正则,并且具有全局g属性,那么match返回的匹配结果,便是一个包含所有匹配结果的纯数组。
    • 如果match的匹配规则是一个正则,并且不具有全局g属性,那么match返回的匹配结果,便是一个包含该匹配结果(只有一个元素)的数组,同时此数组还包括两个对象属性。
    1
    2
    3
    4
    5
    var str = 'abcdabcda';
    var result = str.match(/a/g);
    result //--> [a,a,a]
    result.input //--> undefined
    result.index //--> undefined
split()
  • split() 方法用于把一个字符串分割成字符串数组。
  • 格式:str.split(pattern,length)
    • pattern参数,可以是正则表达式,也可以是单纯的字符或字符串。
    • length参数,用于设置拆分数组后数组最大的长度(即数组元素的个数)。缺省该项,表示将字符全部拆分后作为数组的元素。
  • 根据规则pattern将字符串拆分为数组,拆分后的数组并不包含作为拆分依据的那个参数。
  • 默认情况下是空字符进行拆分,也就是每个任意的字符作为一个数组元素。      
    1
    2
    3
    4
    5
    6
    var str = 'hellow word!';
    str.spilit(''); // --> ''空字符(并非空格字符)["h", "e", "l", "l", "o", "w", " ", "w", "o", "r", "l", "d", "!"]
    str.split('',5) // --> ["h", "e", "l", "l", "o"]
    str.split(/\o/g) // --> ["hell", "w w", "rld!"]
    'a b c'.split(/\s+/); // --> ['a', 'b', 'c'] 可以识别连续的空格
    'a,b, c d'.split(/[\s\,]+/); // ['a', 'b', 'c', 'd']
search()
  • str.search(pattern)
  • 返回第一个与pattern相匹配的子串的起始位置。如果没有找到任何匹配的子串,返回-1。
  • 其功能类似于indexOf,只是indexOf并不支持正则匹配。
  • 注意:该方法忽略全局修饰符g,也不支持lastIndex,也就是意味着它不能被多次调用,一旦检索到结果,便会停止检索。
    1
    2
    3
    var str = 'hellow world!';
    str.search('o') // --> 4
    str.search('x') // --> -1

JS的正则基础语法

  • 正则表达式是由两种字符模式组成,分别是普通字符元字符。通过这两种字符模式的结合使用,可以编写出符合我们要求的正则规则。
  • 普通字符:即由显性的没有特殊含义的打印字符没有指定为元字符的非打印字符组成。
    • 显性的打印字符,它是实际可见的,例如0-9,a-z。
    • 非打印的字符,例如ASCII码值在0-31的为控制字符,它们无法显示和打印,但实际存在。
  • 元字符:元字符更接近计算机语言中的变量含义,它可以代表某种特殊的含义,并且会根据使用场合不同,其具体的含义也不尽相同。
  • 元字符,根据其特性与含义,下面将以几个小类来说明。

转义运算符

  • 功能:对元字符进行转义,使其转换为普通字符。
    1
    2
    3
    var pattern = /\[/;
    var str = '[]';
    console.log(pattern.test(str)) // -> true;

量词(贪婪匹配)

  • ?:表示匹配0次或1次
  • +:表示匹配1次或多次
  • *:表示匹配0次或多次
  • {n}:表示匹配n次
  • {n,m}:表示匹配n到m次
  • {n,}:表示至少匹配n次

边界

  • \b:匹配单词边界,用于匹配一个整体的单词时使用。
  • \B:匹配非单词边界。
  • ^:强制首匹配,以指定规则开始的字符,避免前导的其它字符。
  • $:强制尾匹配,以指定规则结束的字符,避免后导的其它字符。

  • “类”是具有相同特征的集合,是一个泛指。
  • 字符类:
    • [abc]:只根据区间内的内容进行匹配。
  • 范围类:
    • [a-zA-Z0-9]:匹配大小写字符a-z以及数组0-9的范围。
  • 反向类:
    • [^a-z]:取反匹配。匹配不在这个区间范围内的内容。
1
2
3
var str = 'google';
var pattern = /[gle]/;
console.log(pattern.test(str))//true

贪婪模式与非贪婪模式

  • 贪婪模式会按照匹配规则尽可能多的去匹配,一直到匹配失败。
  • 非贪婪模式则会根据最小匹配规则去匹配。
  • 以匹配规则为例来说,贪婪是指匹配所有符合规则的结果,按照最大可能的结果去匹配,而非贪婪则只要有匹配结果便会停止匹配。
  • 从量词上看:* + ?都是贪婪匹配,因为它们都会按照匹配规则尽可能的去匹配。
    • 例如,*匹配零个或多个,但实际匹配上,会以多个的情况为优先匹配。
  • 取消贪婪模式也很简单,在原有的基础上附加上一个?号,这时就改为非贪婪模式,一旦条件满足,就不再往下匹配。    
  • 非贪婪匹配:
    • +? 只匹配一次
    • ?? 匹配 0次
    • *? 匹配0次
    • {n}? 按照n次匹配
    • {n,}? 按照n次匹配
    • {n,m}? 按照n次匹配
1
2
3
4
5
var str = 'aaa',
pattern1 = /a*/,
pattern2 = /a*?/;
pattern1.exec(str); // -> aaa
pattern2.exec(str); // -> ''

分组

  • 分组就是把要匹配的结果作为一个组一个整体来看待。因此只要是属于该分组的信息,都要放在()符号内。
() 捕获性分组
1
2
3
4
5
var str = '123abc';
var pattern = /(\d{4})(\w+)/;
pattern.test(str);
console.log(RegExp.$1) //-> 123
console.log(RegExp.$2) //-> abc
(?:) 非捕获性分组
1
2
3
4
5
var str = '123abc';
var pattern = /(\d{3})(?:\w+)/;
pattern.test(str);
console.log(RegExp.$1) //-> 123
console.log(RegExp.$2) //-> '';
((…)) 嵌套分组
  • 嵌套分组从外向内获取。
1
2
3
4
5
6
var str = 'abc';
var pattern = /(a?(b?(c?)))/;
pattern.test(str);
console.log(RegExp.$1) //-> abc
console.log(RegExp.$2) //-> bc
console.log(RegExp.$3) //-> c

运算符

  • 相同优先级的从左到右进行运算,不同优先级的运算先高后低。各种操作符的优先级从高到低如下:
操作符 描述
\ 转义符
(), (?:), (?=), [] 分组和类
*, +, ?, {n}, {n,}, {n,m} 量词
^, $, \anymetacharacter 边界以及字符顺序
\ “或”操作

其它

修饰符m对位置元字符的影响
  • 修饰符m表示多行匹配,而^$表示匹配的开始于结束位置,这两种情况一起使用,或分别使用的区别:

    • ^$m:不仅匹配字符串的起始于结束位置,还会匹配每一行的起始于结束位置。
    • ^$:只匹配字符串的起始于结束位置。
      1
      2
      3
      4
      5
      var str = 'hellow World\nWorld\naWorld',
      pattern1 = /World$/g;
      pattern2 = /^World$/gm;
      pattern1.exec(str); // -> index:20
      pattern2.exec(str); // -> index:13
  • 由此可以看出,对于正则来说,字符串如果存在多行,那么每一行都会存在^$匹配操作。

\Number 指定重复分组
  • 在分组匹配捕获时,也可以在正则规则中指定\n(注:n:1-9)的形式来代指某个分组的值。
1
2
3
var str = 'abcabc',
pattern = /(.)b(.)\1b\2/;
pattern.test(str); // -> true
  • 一个子表达式是一个整体,可重复后面引用
  • /(\d)(\d)\2\1/gi; 第二位和第三位相同,第一位和第四位相同
  • /(\d)\1(\d)\2(\d)\3(\d)4/; aabbccdd形式的数字
  • /(\d){5}-(\d)\2\2(\d)\3\3(\d)\4\4/gi; 12345-111222333
换行匹配
  • 在正则中字符串的换行是用\n进行表示的。
1
2
3
4
5
var str = '1.baidu\n2.google\n3.bing';
var pattern1 = /\d/g; //此种方式也可以做到,但是建议使用标准的换行模式。
var pattern2 = /^\d/gm;
console.log(str.replace(pattern1,'#'));
console.log(str.replace(pattern2,'#'));
字符匹配符号
  • [a-z]表示可以匹配a-z中任意一个字符
  • [^a-z]表示可以匹配不是a-z中的任意一个字符
  • [abcd]表示可以匹配到abcd中的任意一个字符
  • \d 表示可以匹配0-9的任意一个数字,相当于[0-9]
  • \D 表示可以匹配不是0-9中的任意一个数字,相当于[^0-9]
  • \w 匹配任意英文字符、数字和下划线,相当于[a-zA-Z0-9_]
  • \W 相当于[^a-zA-Z0-9_]是\w刚好相反。
  • \s 匹配任何空白字符(空格、制表符等)
  • \S 匹配任何非空白字符,和\s刚好相反
  • . 匹配除\n之外的所有字符
  • 需要用到转义符号的字符有 : . * + () $ / \ ? [] ^ {}
定位符
  • 用于规定匹配的字符串出现的位置
  • ^符号 匹配目标字符串的开始位置
  • $符号 匹配目标字符串的结束位置

常用正则表达式收集

  1. 匹配任意字符
    • 正则: /[^]/
  2. 匹配ASCII码范围
    • 规则:\x00表示十进制0 ,\xff表示十进制255,0-255正好是ASCII码表可表示的范围。
    • 正则: /[\x00-\xff]/g
    • 说明:同理, /[^\x00-\xff]/g 则表示匹配汉字或者是全角字符。
  3. 匹配汉字
    • 规则:\u4e00 : 在Unicode码中汉字的开始编码,\u9fa5 : 在Unicode码中汉字的结束编码。
    • 正则: /^[\u4e00-\u9fa5]+$/
  4. 手机号码检测
    • 规则:[3|4|5|7|8] : 手机号11位,但是第二位数字只有这几种固定的网段。
    • 正则: /^1[3|4|5|7|8]\d{9}$/
  5. 邮政编码
    • 规则:邮政编码必须为数字,长度为6位且第一位不能为0,示例:224000
    • 正则: /[1-9]\d{5}/
  6. 电子邮件
    • 规则:邮箱的基本格式为“名称@域名”,只允许英文字母、数字、下划线、英文句号、以及中划线组成。
    • 正则: /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$/
  7. 匹配前后空格
    • 正则: /^\s+|\s+$/g
  8. QQ号匹配
    • 规则:首位不能为0,位数5-12位。
    • 正则: /^[1-9]\d{4,11}$/;
  9. 匹配网址url的正则表达式
    • 正则: [a-zA-z]+://[^\s]*
  10. 匹配国内电话号码
    • 正则: \d{3}-\d{8}|\d{4}-\d{7}
  11. 匹配国内身份证号码
    • 规则:简单的身份证匹配,根据位数以及结尾是否有字母。
    • 正则: /^\d{15}(\d{2}[A-Za-z0-9])?$/
  12. 匹配IP地址
    • 正则: /^(\d+).(\d+).(\d+).(\d+)$/g
  13. 验证是否含有^%&’,;=?$\”等字符
    • 正则: /[^%&’,;=?$\x22]+/
  14. 匹配空行的正则表达式
    • 正则: \n[\s| ]*\r
  15. 数学正则
    • 整数 : /^[-+]?\d+$/
    • 浮点数 : /^[-+]?\d+(.\d+)?$/
    • Chinese : /^[\u0391-\uFFE5]+$/
    • 实数: ^[-+]?\d+(.\d+)?$
------ 本文结束 ------