JS中的第二世界--正则表达式

Posted yancy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS中的第二世界--正则表达式相关的知识,希望对你有一定的参考价值。

近期的繁忙让我一直没有空闲静下心来好好写一些文章。好在,所有的忙碌都已过去,愿明天更美好。刚过完七夕,带着欢乐的心情写下这篇文章。希望读者能够喜欢哟~~

你是不是经常遇到正则,却不知它在说什么,你是不是就算再项目中看到了,也会选择一眼略过,你是不是整天忘记搜索什么,却不知道有的编辑器搜索支持正则的模糊搜索……

熟悉的旋律萦绕在耳边,却早已不是当初的少年。

工作了很久之后,猛然发现之前自己忽略的正则是这么重要。搜索、查询、命令行、校验、截取、替换…………哪样哪样都离不开这个小东西。很多人不知道的是,正则在 javascript 里仿佛一个第二世界一样。看起来简单,实则有很多让我们摸不着头脑的操作。

接下来,让我们顺着本文的介绍,一点儿一点儿深入了解正则表达式,知晓正则的强大能力!

1. 创建正则表达式

JavaScript 中创建正则表达式有两种方式

第一种:构造函数创建

const reg = new Reg(\'正则表达式\')

第二种:字面量创建

const reg = /正则表达式/

2. 使用正则表达式匹配内容

正则匹配分为 精准匹配 和 模糊匹配

精准匹配

只需要我们将需要匹配的内容放入到正则表达式中匹配即可。上手简单

const reg = /正则表达式/
const str = \'这是一篇写正则表达式是文章\'

str.match(reg) // 正则表达式

这里的正则表达式会精准的搜索到我们要搜索的内容。

模糊匹配

模糊匹配需要用到第三点所描述的内容,这里我们先看下

const reg = /[\\u4e00-\\u9fa5]+/
const str = \'这是一篇写正则表达式Regpx的内容\'

str.match(reg) // 这是一篇写正则表达式

这里的正则表达式会根据我们传入的规则来匹配要搜索的内容。注意:这里的\\u4e00-\\u9fa5表示的是中文范围

\\u4e00 表示的是字符集中第一个中文汉字

\\u9fa5 表示的是字符集中最后一个中文汉字

ok,知道了怎么创建和使用正则,接下来我们来真正了解一下他吧。

3. 正则表达式介绍

通晓元字符的同学可跳过此小节,直奔第四小节查看。主要内容有 . | \\ * + ? () [] {} ^ $ 几种字符使用方法,含义和注意事项,内置匹配项,贪婪和惰性匹配。

首先介绍一下前瞻条件,正则可以根据自己的设置来进行多行和全局,局部,忽略大小写等匹配模式,分为:

  • m :多行匹配
  • g: 全局匹配
  • i: 忽略大小写

接下来的内容,就可以看到我们来使用它

3.1 元字符

元字符是正则表达式中最基础的部分,它代表了我们可以查询的内容。come on baby。让我们来认识一下他们吧。

  • . :匹配除去 \\n 之外的所有内容
const reg = /.*/
const str1 = \'abc\'

// 在str2中添加 \\n 换行符
const str2 = \'a\\nb\\nc\'

str1.match(reg) // abc
str2.match(reg) // a
  • |:在正则中进行逻辑判断,(说的比较抽象,我们来看下例子)
const reg = /正则|表达/
const str1 = \'正则表达式\'
const str2 = \'表达式\'

str1.match(reg) // 正则
str2.match(reg) // 表达

解释:

如果可以匹配到 | 前边的内容,则匹配前边的。

匹配不到前边的,但是可以匹配后边的内容,则匹配后边的

  • 反斜杠 \\ :表示转义
const reg = /\\./
const str = \'a.b.c.d\'

str.match(reg) // .

可以匹配除 \\n 外任意字符的点 . 在使用 \\ 转义之后只能匹配到 . 这个字符

需要注意的点:

在有的编程语言中,匹配 \\\\ 需要四个反斜杠 -- \\\\\\\\。但是在 javascript 中,只需要两个。

const reg = /\\\\/
const str = \'\\\\\'

str.match(reg) // \\\\
  • 星号 *:需要匹配的内容出现连续零次或多次
const reg = /a*/
const str1 = \'aaabbcccddd\'
const str2 = \'bbcccddd\'
reg.test(str1) // true
reg.test(str2) // true
  • 加号 +:需要匹配的内容出现连续一次或多次
const reg = /a+/
const str1 = \'aaabbcccddd\'
const str2 = \'bbcccddd\'
reg.test(str1) // true
reg.test(str2) // false
  • 问号 ?:需要匹配的内容出现连续零次或一次
const reg = /a?/
const str1 = \'aaabbcccddd\'
const str2 = \'bbcccddd\'

reg.test(str1) // true
reg.test(str2) // true
  • 小括号(): 表示组,小括号中的内容表示一组,整体进行匹配。
const reg = /(abc)/
const str1 = \'abab\'
const str2 = \'abcab\'
reg.test(str1) // false
reg.test(str2) // true

拓展:

使用小括号包裹的匹配内容,可在后续的正则中通过\\ + 序号的方式继续调用。有几个小括号就有几个序号。序号从1开始

const reg = /(abc)\\1/  // 相当于 const reg = \'(abc)abc\'
const str = \'abcabc\'

str.match(reg)

//   /(a)(b)(c)\\1\\2/ ---> /(a)(b)(c)ab/
  • 中括号 []:表示范围,括号中的内容只要有一个匹配到就可以
const reg = /[abc]/
const str = "efg"
const str1 = \'aef\'

reg.test(str) // false
reg.test(str1) // true

注意:

中括号中可以使用 - 来表示连续的范围

/[0-9]/   0123456789
/[a-z]/   全部英文小写
/[A-Z]/   全部英文大写
  • 大括号 {m,n}:表示出现次数

    m 表示最少出现多少次 n表示最多出现多少次,n可省略,表示无限次

const reg = /a{1,4}/ // a最少出现1次,最多出现4次
const str = \'aaaaa\'

reg.test(str) // true

拓展:

{0,} 相当于 *

{1,} 相当于 +

{0,1}相当于 ?

  • 开头^:只匹配开头内容
const reg = /a^/
const str = \'abc\'
const str1 = \'bac\'

reg.test(str) // true
reg.test(str1) // false

注意:

此符号用在 [] 中,表示取反操作

const reg = /[^abc]/g 
const str = \'123\'
str.match(reg) // [\'1\', \'2\', \'3\']

这里只能取到不是 abc 的内容

  • 结尾$: 只匹配结尾
const reg = /a$/
const str = \'abc\'
const str1 = \'cba\'

reg.test(str) // false
reg.test(str1) // true

3.2 内置匹配符

\\d:数字

\\D:非数字

\\s:空格

\\S:非空格

\\w:数字字母下划线

\\W:非数字字母下划线

\\b:字符边界

\\B:非字符边界

const str = \'hello word! 520\'

console.log(str.replace(/\\d/g, \'*\')) // hello word! ***
console.log(str.replace(/\\D/g, \'*\')) // ************520
console.log(str.replace(/\\w/g, \'*\')) // ***** ****! ***
console.log(str.replace(/\\W/g, \'*\')) // hello*word**520
console.log(str.replace(/\\b/g, \'*\')) // *hello* *word*! *520*
console.log(str.replace(/\\B/g, \'*\')) // h*e*l*l*o w*o*r*d!* 5*2*0
console.log(str.replace(/\\s/g, \'*\')) // hello*word!*520
console.log(str.replace(/\\S/g, \'*\')) // ***** ***** ***

3.3 贪婪和惰性

贪婪匹配是最多情况下匹配内容

惰性匹配是最少情况下匹配内容

先看栗子

const reg = /a[bc]*c/g  // 贪婪
const str = \'abcbcbc\'

console.log(str.match(reg)) // [ \'abcbcbc\' ]

const reg1 = /a[bc]*?c/g // 惰性
console.log(str.match(reg1)) // [ \'abc\' ]

解释:

  • 贪婪: 由于 abcbcbc 一直到字符串最后都符合正则的规则,所以一直匹配到不符合位置
  • 惰性:只匹配一个符合规则的就返回,不继续匹配。

4. 正则进阶操作

4.1 具名组匹配

JavaScript 中提供了组匹配的能力。可以同过自定义的组名来获取匹配内容.

组的固定格式为 ?<组名>。然后通过获取结果的groups.具体的名称 来获取

const reg = /(?<name>[a-zA-Z]{3,6})(?<age>\\d{2})/
const str = \'xiaoming23\'

str.match(reg).groups.name // xiaoming
str.match(reg).groups.age // 23

4.2 位置匹配

  • ?=搜索内容:查看右侧内容是否符合条件, 查看后缀是否为要搜索的内容。
const reg = /(?=abc)/
const str = \'efabcefabc\'

str.replace(reg, \'*\') // ef*abcef*abc

解释:

匹配 后缀为abc 这个字符的位置

  • ?!搜索内容:查看右侧内容是否不符合条件,查看后缀是否为要搜索的内容
const reg = /(?!abc)/
const str = \'efabcefabc\'

str.replace(reg, \'*\') // *e*fa*b*c*e*fa*b*c*

解释:

匹配 后缀不为 abc 这个字符的位置

  • ?<=搜索内容:查看左侧内容是否符合条件,查看前缀是否是要搜索的内容
const reg = /(?<=abc)/
const str = \'efabcefabc\'

str.replace(reg, \'*\') // efabc*efabc*

解释:

匹配 前缀为abc 这个字符的位置。

  • ?<!搜索内容:查看左侧内容是否不符合条件
const reg = /(?<!abc)/
const str = \'efabcefabc\'

str.replace(reg, \'*\') // *e*f*a*b*ce*f*a*b*c

解释:

匹配 前缀不为abc 这个字符的位置。

第四小节总结:

  1. 组匹配 ?<组名>
  2. 匹配后缀 ?=?!
  3. 匹配前缀 ?<=?<!

5. 正则和字符串方法介绍

5.1 字符串方法

下述方法都支持正则匹配方式来操作。

  • replace(reg, 替换的内容 或者 一个操作函数) 替换

    此方法的第二个参数是比较神奇的,可以接收要替换的内容,也可以接受一个函数。

    • 为替换内容(1)
    const str = \'abc\'
    str.replace(/a/, \'*\') // *bc
    • 为替换内容(2)

      可使用 $1,$2………… 等变量作为匹配到的组的内容。

    const str = \'123abc\'
    str.replace(/(a)(b)(c)/, \'$1$3$2\') // 123acb

    说明:

    $1 代表 (a) 所匹配到的内容

    $2 代表 (b) 所匹配到的内容

    $3 代表 (c) 所匹配到的内容

    替换的时候掉到顺序替换,则输出 123acb 这个值

    • 为函数
    const str = \'abc\'
    str.replace(/(a)/, (source, $1, index) => {
      console.log(source, $1, index) // abc  a  0
      return *
    }) // *ab
    
    str.replace(/(b)(c)/, (source, $1, $2, index) => {
        console.log(source, $1, $2, index) // abc 
        return $1 + 1
    }) // a11

    说明:

    函数参数接收的参数,第一个source 为字符串本身,最后一个index为查找到的第一个索引值。中间的 $1, $2, $3……………… 为正则表达式里小括号的数量。返回值的作用是作为替换内容替换原字符串。

  • match 搜索

    根据正则的规则匹配字符串

    const reg = /[abc]/g
    const str = \'abc\'
    
    str.match(reg) // [ \'a\', \'b\', \'c\' ]
  • split 切割

    const str = \'abcabcabc\'
    
    str.split(/ca/) //[ \'ab\', \'b\', \'bc\' ]

    此方法还可接收第二个参数。length 设置返回的数组长度

    const str = \'abcabcabc\'
    
    str.split(/ca/, 2) //[ \'ab\', \'b\' ]

5.2 正则方法

  • test 查看字符串是否符合正则规则

    const reg = /abc/
    const str = \'abc\'
    const str1 = \'ab\'
    
    reg.test(str) // true
    reg.test(str1) // false
  • exec 根据正则的规则匹配字符串。同 match

    const reg = /abc/
    const str = \'abc\'
    const str1 = \'ab\'
    
    reg.exec(str) // \'abc\'
    reg.exec(str1) // null

6. 实战篇

理解了内容之后怎么也得练练手啊,此内容给大家准备了几个常见但是不太好理解的正则,请大家练手。

6.1 匹配 html 标签 (包含标签中的内容)

首先,我们来创建个字符串

const html = \'<div></div>\'

现在我们来抒写一下可描述标签的正则表达式。有以下几个特征:

  1. < 开头
  2. 标签名为英文字符
  3. </标签名> 结尾
第一版表达式
const reg = /<(\\w+)><\\/(\\1)>/g

// 验证一下
html.match(reg) // \'<div></div>\'

\\1引用上一个分组的正则规则上面的内容已经说过。

看我们的验证结果,完美。但是,有个问题。我们的标签一般都不在一行内书写,标签之间会有 \\n 来标识换行。ok,让我们修改一下 html 字符串

const html = `<div>

</div>`

// 再次验证
html.match(reg) // null

以上是关于JS中的第二世界--正则表达式的主要内容,如果未能解决你的问题,请参考以下文章

关于JS 中正则表达式第一次判断为 true,第二次判断为false的问题

js使用正则表达式获取字符串中特定的字符

JS中的正则表达式匹配

JS正则表达式

通过 Java 正则表达式提取 semver 版本字符串的片段

js正则表达式过滤以指定字符开头以指定字符结尾的文本内容