javascript正则表达式

1,186 阅读6分钟

一、REGEXP对象

JavaScript通过内置对象RegExp支持正则表达式 有两种方法实例化RegExp对象:

  • 字面量:var reg = /\bis\b/g;
  • 构造函数
var reg = new RegExp ('\\bis\\b','g');
//两个\是因为在字符串中\需要转义

修饰符:

g:全文搜索,不添加,搜索到第一个匹配为止

i:忽略大小写,默认大小写敏感

m:多行搜索

对于有换行符/n的正则表达式,在document.write();中会被识别为分隔符即空格,因此要看出换行效果,只能console.log。 正常情况下键盘的回车等于 /r/n,/r等于一行的结束, /t代表制表符Tab。

二、正则表达式组成

1.元字符

  • 原意文本字符:代表它本来意思的字符,比如a,b,c就代表a,b,c
  • 元字符:在正则表达式中有特殊含义的非字母字符
* + ?¥ ^ . | \ () {} []
\t		水平制表符
\v		垂直制表符
\n		换行符
\r		回车符
\0		空字符
\f		换页符
\cX	与X对应的控制字符(Ctrl + X)

2.字符类

一般情况下正则表达式一个字符对应字符串一个字符:

  • 可以使用元字符[]创建一个简单的类
  • 类是指符合某些特性的对象,一个泛指,而不是特指某个字符
  • 表达式[abc]把字符abc归为一类,表达式可以匹配这类的字符

3.字符类取反

  • 使用元字符^创建反向类/负向类
  • 反向类的意思是不属于某类的内容
  • 表达式[^abc]表示不是字符a或b或c的内容

4.范围类

  • 可以使用[a-z]来连接两个字符表示从a到z的任意字符
  • 闭区间,包含az本身
  • []组成的类内部是可以连着写的[a-zA-Z],表示大写和小写字母

5.预定义类

  • 匹配常见的字符类
字符 等价类 含义
. [^\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] 非单词字符
  • 匹配一个ab+数字+任意字符的字符串: ab\d.

6.边界

常用边界匹配字符:

字符 含义
^ 以***开始
$ 以***结束
\b 单词边界
\B 非单词边界

注意:在不同的场景中部分字符的含义是不同的 比如^[]中是取反,不在就是以***开始

7.量词

字符 含义
出现零次或一次(最多出现一次)
+ 出现一次或多次(至少出现一次)
* 出现两次或多次(任意次)
{n} 出现n次
{n,m} 出现n到m次
{n,} 至少出现n次

8.贪婪模式和非贪婪模式

  • 贪婪模式:正常情况下\d{3,6}会尽可能多的匹配数字,即全部以6为单位匹配(直到没有六个)
  • 非贪婪模式:让正则表达式尽可能少的匹配,也就是说一旦成功匹配不再继续尝试,以最少的单位匹配
\d{3,6}?					在量词后加?变成非贪婪模式

9.分组

  • 正常量词只能匹配到最后一个字母,比如beyond{3},是匹配d字母3次
  • 使用()加入分组功能,是量词作用单词,比如(beyond){3}
  • 使用|达到或的效果
  • 反向引用,巧用$分组捕获

10.前瞻

正则表达式从文本头部向尾部开始解析,文本尾部方向称为“前”,前瞻就是在正则表达式匹配到规则的时候,向前检查是否符合断言,后顾方向相反。

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

断言部分assert也是正则表达式。

三、正则表达式相关的方法

1. 正则对象属性

  • global:是否全文搜索,默认为false

  • ignore case:是否大小写敏感,默认为false

  • multiline:多行搜索,默认值是false

  • lastIndex:是当前表达式匹配内容的最后一个字符的下一个位置,特别注意这个属性,在全局模式g下很容易出错,具体看:lastindex属性

  • source:正则表达式的文本字符串

2.正则对象方法

RegExp.prototype.test(str)
  • 用于测试字符串参数中是否存在匹配正则表达式模式的字符串
RegExp.prototype.exec(str)

使用正则表达式模式对字符串执行搜索,并将更新全局RegExp对象的属性以反映匹配结果。

  • 若没有匹配的文本则返回null
  • 否则返回一个结果数组: index:声明匹配文本的第一个字符的位置 input:存放被检索的字符串string

3.字符串对象方法

在字符串方法中可以使用正则表达式

(1)String.prototype.search()

用于检测字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串。 str.search(reg) 返回第一个匹配结果index,没找到返回-1

(2)String.prototype.match()

检索字符串,找到一个或多个与regexp匹配的文本,是否具有g对结果影响很大。

  • 若无g,那么match方法只能在字符串中执行一次匹配,返回匹配到的字符串或null
  • 有g,返回一个数组,存放匹配到的所有文本的相关信息
(3)String.prototype.replace(reg, replacement)

replace 方法用 replacement 替换对应的匹配,返回替换后的字符串。

replacement 可以是

  • 字符串
  • 函数,函数的参数是匹配到的字符串 但是不能是箭头函数,因为箭头函数不能取到匹配到的字符串。

下面是几个 replace 的例子:

// 1.get-element变成驼峰式
function commal(str) {
  // 不规定个数都是自动匹配一个
  // 一定要加全局修饰符
  let reg = new RegExp('-[a-z]', 'g')
  // $0 是replace匹配到的字符串
  // replace方法不改变原有字符串
  return str.replace(reg, function($0) {
    return $0.slice(1).toUpperCase()
  })
}

console.log(commal('ab-gi-du'))    // abGiDu
// 2.分割数字每三个以一个逗号划分
function slicestr(str) {
  let reg = /\d{3}/
  // 这个是正确的,不会出现 123,256, 的情况
  //let reg = /(\d)(?=(\d{3})+$)/g;
 
  // 使用箭头函数,取不到 匹配到的字符串,最后返回 undefined
  /* return str.replace(reg, (word) => {
    word + ','
  }) */
  return str.replace(reg, function(word) {
    return word + ','
  })
}
(4)split()方法

四、几个方法的对比

1.RegExp.prototype.test(str) 和 String.prototype.search(reg)

这两个方法都可以用来查找字符串 str 中是否有对应的正则表达式字符串,但有以下不同:

  • text 是正则对象的方法,search 是字符串对象的方法
  • text 在全局模式下与 RegExp.lastIndex 配合使用,每次都从上一次匹配的位置出发
  • text 返回布尔值,只判断是否存在匹配,而 search 返回第一个匹配到的位置,没有则返回 -1
let str = "k is so k"
// 全局模式
let reg = new RegExp("k", "g")
console.log(reg.test(str))    //true
console.log(reg.lastIndex)    // 1
console.log(reg.test(str))    //true
console.log(reg.lastIndex)    // 9
// 全局模式
let str = "k is so k"
let reg = new RegExp("k", "g")
console.log(str.search(reg))  // 0
console.log(reg.lastIndex)    //0
console.log(str.search(reg))  //0
console.log(reg.lastIndex)    // 0

2.RegExp.prototype.exec(str) 和 String.prototype.match(reg)

exec 和 match 方法都可以返回有 索引位置index 属性的对象,但两者的具体使用与是否在全局模式下有关系。

  • exec 在非全局模式下每次返回第一个匹配对象,在全局模式下和 lastIndex 属性配合使用,每次都向后查找一个,返回对应的匹配对象。
let str = "k is so k"
// 非全局模式
let reg = new RegExp("k")
console.log(reg.exec(str))    // {"0: "k"
                              // groups: undefined
                              // index: 0
                              // input: "k is so k k k"
                              // length: 1"}
console.log(reg.lastIndex)    //  0
console.log(reg.exec(str))    // 同上
console.log(reg.lastIndex)     // 0
// 全局模式
let str = "k is so k"

// 非全局模式
let reg = new RegExp("k", "g")
console.log(reg.exec(str))    // {"0: "k"
                              // groups: undefined
                              // index: 0
                              // input: "k is so k"
                              // length: 1"}
console.log(reg.lastIndex)    //  0
console.log(reg.exec(str))    // {"0: "k"
                              // groups: undefined
                              // index: 8
                              // input: "k is so k"
                              // length: 1"}
console.log(reg.lastIndex)     // 9
  • match 在全局模式下直接返回 匹配对象数组,没有位置 index 等信息,在非全局模式下返回第一个对象的匹配对象,包含 index 等信息。
// 全局模式
let str = "k is so k"
let reg = new RegExp("k", "g")
console.log(str.match(reg))   // ["k", "k"]
console.log(reg.lastIndex)    // 0
console.log(str.match(reg))   // ["k", "k"]
console.log(reg.lastIndex)    // 0

// 非全局模式
let str = "k is so k"
let reg = new RegExp("k", "g")
console.log(str.match(reg))   // {"0: "k"
                              // groups: undefined
                              // index: 0
                              // input: "k is so k"
                              // length: 1"}
console.log(reg.lastIndex)    // 0
console.log(str.match(reg))   // 同上
console.log(reg.lastIndex)    // 0

参考

MDN正则表达式

可能是最好的正则表达式教程的笔记