javascript正则表达式

javascript正则表达式

正则表达式使用来匹配字符串中具有一定规律字符组合的模式,在实际的开发中使用频率还是比较高的,强大的正则表达式,能够极大的方便我们对字符串的操作,提高我们的开发效率。本文将由浅入深,剖析javascript中的正则表达式。

### 正则表达式的创建

javascript通过内置对象 RegExp 支持正则表达式,有两种方式可以实例化 RegExp 对象。

  1. 字面量形式
    let reg = /a/g 表示全局匹配一个字母a
  2. 构造函数的形式
    let reg = new RegExp('a'[,修饰符]) 全局匹配一个字母a
  3. 对象属性
    global:g,全文搜索,默认false
    ignoreCase:i,忽略大小写搜索,默认false
    multiline:m,多行搜索,默认false
    lastIndex:当前被匹配内容的最后一个字符的下一个位置
    source:正则表达式的文本字符串

### 元字符

在正则表达式中,有一种是表示字符本身含义的字符,如字符a就表示一个a字母,还有一类就是表示一些特殊含义的非字母字符,主要有如下元字符
()[]{}?+*^$.|
元字符在不同的情景下可能会有不同的含义,如^,在正则表达式开始表示边界,在[]中表示取反

### 具有特殊含义的字符

字符 含义
\t 水平制表符
\v 垂直制表符
\r 回车符
\n 换行符
\0 空字符
\f 换页符
\cX 与X对应的控制字符(如ctrl+X)

### 字符类

  1. 简单类

    一般情况下正则表达式的一个原义字符对应匹配一个字符,如/a/匹配一个字符a,/ab/匹配字符ab,但是我们可以用[]将一组字符括起来,让它们整体来表示一个字符,表示匹配[]中的其中的一个字符,如[abc]可以匹配单个的a或b或c字符
    ---
    javascript console.log(/[abc]/g.test('a')) //ture console.log(/[abc]/g.test('b')) //ture console.log(/[abc]/g.test('c')) //ture

  2. 负向类

    仍然是在[]中,加上一个^,表示取反,即匹配不能为[]中的任意一个字符
    如:/[^abc]/表示被匹配的字符串不能为abc中的任意字符
    ---
    javascript console.log(/[^abc]/g.test('a')) //false console.log(/[^abc]/g.test('b')) //false console.log(/[^abc]/g.test('d')) //true console.log(/[^abc]/g.test('da')) //true

  3. 范围类

    如果我们想匹配abcdefg这几个字符串中的任意一个,我们可能会写/[abcdefg]/,但是这样写起来太麻烦,可读性也很差,对于这种有明显的排列顺序规则的,我们可以使用范围类来进行匹配,即在中间加 -,上面的例子可改写为/[a-g]/

  4. 预定义类

    对于一些常见的匹配,我们可以用一些特殊的字符来表示,以简化我们的书写

字符 等同于 含义
. [^\r\n] 除了换行符和回车符以外的任意一个字符
\d [0-9] 数字字符
\D [^0-9] 非数字字符
\s [\t\n\r\f\xOB] 空白字符
\S [^\t\n\r\f\xOB] 非空白字符
\w [a-z0-9_A-Z] 单词字符(所以的字符,数字和_)
\W [^a-z0-9_A-Z] 非单词字符

### 量词

我们已经知道上述的字符类,都只是进行一对一的匹配,即只是匹配一个字符,但是如果我们要匹配一个字符串,如匹配50个单词字符,那我们需要将\w写50次,这岂不是逼死人的节奏。还好我们有量词来简化这种操作

  1. 简单量词
规则 含义
? 出现零次或一次
+ 出现一次或多次(至少出现一次)
* 出现零次或多次(出现任意次,也可以不出现)
{n} 出现n次
{n,m} 至少出现n次,但不超过m次(大于等于n,小于等于m次)
{n,} 至少出现n次
  1. 贪婪模式与非贪婪模式

    首先我们来想一下这个例子,'abcdefg'.replace(/\w{4,7}/g,'x')/\w{4,7}/g既可以匹配上abcd,也可以匹配上abcdefg,那到底是那一部分会被替换掉了,这就引出了我们所说的贪婪模式与非贪婪模式

  • 贪婪模式
    • 贪婪模式顾名思义,就是尽可能多的进行匹配。
    • 简单量词匹配都属于贪婪模式。
    • 我们不难得到,上面的例子属于贪婪模式,会尽可能多的匹配,也就是abcdefg会被替换成x
  • 非贪婪模式
    • 非贪婪模式与贪婪模式相反,就是尽可能少的进行匹配
    • 实现方式,在简单量词后面加?
    • 将上面的例子改写为非贪婪模式 'abcdefg'.replace(/\w{4,7}?/g,'x'),则abcd会被替换为x,得到的结果为xefg

### 分组

如果需要一个像victorvictor的匹配模式,那我们应该怎么写呢,像victor{2}?这表示的是r出现2次,显然是达不到我们的目的的。这是我们可以通过用()victor括起来,使其成为一个整体,也就是分组。即/(victor){2}/就可以达到我们的目的了。

### 反向引用

如果我们想将yyyy-mm-dd的日期格式变为mm/dd/yyyy,我们应该如何做呢?这就需要我们捕获到匹配的年月日,然后进行重新组合

  • 我们可以通过反向引用来获取到分组匹配到的字符,每个反向引用都有类似$1,$2的编号来表示
  • 上述例子我们可以写成 '2018-05-04'.replace(/([\d]{4})-([\d]{2})-([\d]{2})/g,'$2/$3/$1')
    • $1表示2018,$2表示05,$3表示04
  • 如果是分组中套用分组,反向引用又该如何表示呢
    • /(victor (and victor){2}){3}/
    • $1:group#1 $2:group#2

      ### 非捕获性分组

      从上面可以看出,每一个分组都会对应一个反向引用,但是如果我们需要某个分组不对应反向分组,该怎么办呢?

  • 通过在分组前面加上?:就可以创建一个非捕获性分组了
  • /([\d]{4})-[\d]{2}-([\d]{2})/

### 候选

我们可以在正则表达式中插入|,将其拆分为多个候选项

  1. /Kobe|James/ 相当于Kobe或者James

  2. /Ko(be|Ja)mes/

前瞻

我们通过某一正则匹配模式匹配到一个字符串后,还可以通过前瞻来检查该字符串接下来的字符串是否符合我们的要求

语法 名称 含义
(?=exp) 正向前瞻 检查接下来的字符符合exp匹配
(?!xp) 负向前瞻 检查接下来的字符不符合exp匹配
  • /victor(?=\d{4})/
    • javascript console.log(/victor(?=\d{4})/.test('victor12')) //false
  • /victor(?!\d{4})/
    •   console.log(/victor(?=\d{4})/.test('victor12')) //true
  • 前瞻是不会被捕获的,也就是说(?=exp)不会对应一个反向引用

边界

语法 含义
^ 非[]中,以...开头
$ 以...结尾
\b 单词边界
\B 非单词边界

正则表达式常用的方法

  1. RegExp.prototype.test(str)

    用来测试被测试的字符串是否能够匹配该正则表达式.匹配上则返回true,否则false

  • 不包含 g 修饰符的非全局调用

javascript let reg1 = /\w/; let str = 'ab' console.log(reg1.test(str),reg1.lastIndex) //true 0 console.log(reg1.test(str),reg1.lastIndex) //true 0 console.log(reg1.test(str),reg1.lastIndex) //true 0 console.log(reg1.test(str),reg1.lastIndex) //true 0
非全局的模式下,lastIndex一直是0,不生效

  • 包含 g 修饰符的全局调用
    javascript let reg1 = /\w/g; let str = 'ab' console.log(reg1.test(str),reg1.lastIndex) //true 1 console.log(reg1.test(str),reg1.lastIndex) //true 2 console.log(reg1.test(str),reg1.lastIndex) //false 0 console.log(reg1.test(str),reg1.lastIndex) //true 1 console.log(reg1.test(str),reg1.lastIndex) //true 2 console.log(reg1.test(str),reg1.lastIndex) //false 0
    如上,在全局模式下,每执行一次test(),都会改变lastIndex的位置,下次再执行test函数时,从lastIndex的位置开始查找

建议:只是使用test检测某个字符串是否含有某个文本时,正则表达式不加g修饰符

  1. RegExp.prototype.exec(str)

    • 使用正则表达式对字符串进行搜索,并将更新全局RegExp对象的属性以反映匹配结果
    • 如果没有匹配到文本则返回null,否则返回一个数组,该数组包含两个属性:
    • index 声明匹配文本的第一个字符的位置
    • input 存放被检索的字符串string
  • 不包含g修饰符的非全局调用

    调用非全局的RegExp对象的exec()时,返回的数组
    • 第一个元素是与正则表达式相匹配的文本
    • 第二个元素是与第一个分组相匹配的文本(如有)
    • 第三个元素是与第二个分组相匹配的文本(如有)
    • ...
      let reg1 = /\w/;
      let str = '$ab';
      let temp = reg1.exec(str);
      console.log(temp,temp.index,temp.input,reg1.lastIndex)  //['a']  1 "$ab"  0
      temp = reg1.exec(str);
      console.log(temp,temp.index,temp.input,reg1.lastIndex)  //['a']  1 "$ab"  0
      temp = reg1.exec(str);
      console.log(temp,temp.index,temp.input,reg1.lastIndex)  //['a']  1 "$ab"  0
      temp = reg1.exec(str);
      console.log(temp,temp.index,temp.input,reg1.lastIndex)  //['a']  1 "$ab"  0

    非全局的模式下,每次执行的结果都一样,只会查找第一个匹配项,lastIndex一直是0,不生效

  • 包含g修饰符的全局调用
    javascript let reg1 = /\w/g; let str = '$ab'; let temp = reg1.exec(str); console.log(temp,temp.index,temp.input,reg1.lastIndex) //['a'] 1 "$ab" 2 temp = reg1.exec(str); console.log(temp,temp.index,temp.input,reg1.lastIndex) //['b'] 2 "$ab" 3 temp = reg1.exec(str); console.log(temp,reg1.lastIndex) //null 0 temp = reg1.exec(str); console.log(temp,temp.index,temp.input,reg1.lastIndex) //['a'] 1 "$ab" 2
    如上,在全局模式下,每执行一次exec(),都会改变lastIndex的位置,下次再执行exec函数时,从lastIndex的位置开始查找

__如果您觉得此文对您有帮助,请扫描下面二维码支持我吧。您的支持是我不断努力的动力^_^__

猜你喜欢

转载自www.cnblogs.com/manba/p/8995290.html