正则小白读《正则表达式必知必会》感悟之二

163 阅读3分钟

贪婪和懒惰匹配

我们看个例子:

const text = '<div>hello</div><div>kkk</div>'
const reg = /<div>.*<\/div>/g
console.log('匹配内容', text.match(reg))
// 输出:匹配内容 ["<div>hello</div><div>kkk</div>"]

我们的本意是匹配的结果是这样的[<div>hello</div>, <div>kkk</div>],即找到每一对div标签。 结果输出匹配的却是,从开头的div标签到结尾的div的所有内容。为什么会出现这种情况呢?

是因为*, +, {n, }是贪婪型元字符,他们匹配规则是多多益善,而不是适可而止。这句话,是怎么理解的呢。

const reg = /<div>.*<\/div>/g

我们看看上述的正则,其意思是匹配以<div>开始 + 任意字符 + </div>结尾,且不区分大小写的。

image.png

贪婪匹配的意思:吃着碗里,看着锅里。利益最大化的代表。

懒惰匹配的意思:就是跟贪婪相反的,吃着碗里,绝不看着锅里。目光短浅的代表。

那如果我们想要懒惰匹配的话,我们应该怎么写呢?只需要在这些*, +, {n, }贪婪型元字符,添加?即可。 即*?, +?, {n,}?

还是上述的例子,我们想要达到我们初始想要的那种需求,即找出每一对div标签内容,那就需要把正则调整成 下面这种形式。

const text = '<div>hello</div><div>kkk</div>'
const reg = /<div>.*?<\/div>/g
console.log('匹配内容', text.match(reg))
// 匹配内容 (2) ["<div>hello</div>", "<div>kkk</div>"]

位置匹配

  • 字符串的边界:^代表字符串的开始,$代表字符串结尾。就是代表你需要匹配的字符串, 必须以^后面的字符开头,$前的字符结尾,才是符合我们查找的字符串,不然则不是。

详细的使用方法,请看下面示例

const text = 'ben';

// 下面三种写法,都能匹配到text
const reg1 = /^ben$/ // 这个代表查找,字母b开头,且中间为字母e, 结尾是必须是字母n的字符串
const reg2 = /^be./ // 这个代表查找,字母b开发,中间为字母e, 结尾为任意字符的字符串
const reg3 = /.*n$/ // 这个代表查找,开头为0个或者多个任意字符且结尾为n的字符串

console.log(text.match(reg1))
console.log(text.match(reg2))
console.log(text.match(reg3))

// 输出的结果为
// [ 'ben', index: 0, input: 'ben', groups: undefined ]

我们稍微改写下上面的那个例子

const text = 'ben ben ben';
const reg1 = /^ben$/g // 由于text文本存在多个ben和空格,导致匹配为null
const reg2 = /^be./g 
// 刚好匹配到第一个ben,因为text就是以字母b开头的,满足正则条件的就是第一个ben字符串
const reg3 = /.*n$/g // 匹配到整个字符串ben ben ben, 因为text的末尾刚好是n

console.log(text1.match(reg1))
console.log(text1.match(reg2))
console.log(text1.match(reg3))

// 输出的结果为
null
[ 'ben' ]
[ 'ben ben ben' ]

  • \b 代表单词边界,匹配一个单词的开始和结尾的位置,即匹配的单词字符,前后不能有\w的字符跟着。

    1. \w(小写)单词构成单词字符 (等价于 [A-Za-z0-9_])
    2. \W(大写)不能构成单词的字符(等价于 /[^A-Za-z0-9_]/)
    3. 只是匹配一个位置,并不匹配任何字符
    4. /\bcap\b/ 匹配的是cap这三个字符,并不是5个字符
const text = 'ben is ben is ben'
const reg = /\bben\b/ // 代表的意思:ben这个词前后,都没有字符跟着
const reg1 = /\bben\b/g
console.log(text.match(reg)) 
// 我们可以看出,\b不匹配字符的,仅仅只是一个占位而已
// 输出: ['ben', index: 0, input: 'ben is ben is ben', groups: undefined]
console.log(text.match(reg1))
// 输出:  ['ben', 'ben', 'ben']

const reg2 = /e\b/
console.log(text.match(reg2))
// 输出:null
// 因为字母e,后面还有字母n, 那就不代码单词的边界

const text3 = 'ben is b_%en% is ben'
const reg3 = /\bb_%en\b/g
// 这个正则的意思:b_%en的字符前后都没有符合\w的字符跟着。
console.log(text3.match(reg3))
// 输出:['b_%en']
  • \B将匹配一个前后都不能构成单词的位置,即跟\b相反的

    例如: xxx - xxx \B-\B 将匹配中间的连字符(即中横线),因为刚好xxx的后面有空格,符合\B + - + xxx前面的空格\B

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 8 天,点击查看活动详情