JavaScript RegExp()构造函数中使用字符串或模版字符串的理解
先上一个小例子:
const regex1 = /\d+/;
const regex2 = new RegExp("\d+");
这是一个匹配多个数字的正则,为什么这里使用RegExp构造函数时,需要用两个斜杠?
因为这里有两层转义机制在同时工作:
使用new RegExp("\d+")时,字符串 "\d+" 会先被 JavaScript 字符串解析器 处理:
然后,这个字符串 \d+ 被传递给 RegExp 构造函数,正则表达式引擎看到的是:
\d 被解释为 匹配数字 的正则元字符+ 被解释为 量词也就是说我们使用new RegExp()构造函数时,目标是为了得到类似\d+这样的字符串,但是由于字符串中的转义机制,使得用起来变得麻烦了一点。
为什么会有转义机制呢? 原来是为了在字符串中表示一些特殊字符,例如单引号、双引号、换行等,我们约定使用转义字符 \ 来进行转义,例如:
\' 表示单引号\" 表示双引号\n 表示换行\t 表示制表符当转义字符 \ 遇到上面的符号就能正确表示出来,如果转义字符 \ 后面碰到了它不认识的字符,他就会原封不动的返回,如 "\a" => "a",这就导致我们不能在字符串中单独使用 "\" 表示一个 '\' 符号,必须使用 '\' 表示
明白了转义机制,再来使用RegExp构造函数时,就会变得简单了很多。
我们只要清楚目标正则表达式是什么样的,然后让字符串能转成这个正则表达式,就可以轻松使用RegExp构造函数传递字符串。
现在来一个难一点的例子。现在要在一段markdown字符串中,拿到其中所有的图片链接
// markdown 图片链接格式: 
// 其中 name 是图片的名称,url 是图片的地址
// 正则表达式
const reg1 = /!\[.+?\]\(.+?\)/g;
// RegExp 传递字符串
const reg2 = new RegExp("!\[.+?\]\(.+?\)",'g');
const markdown = "\n";
const result = markdown.matchAll(reg2)
result.forEach(item=>console.log(item))
目标字符串: !\[.+?\]\(.+?\)
用字符串表示时需要将 \ 用 \ 转义,最后得到 :!\[.+?\]\(.+?\)
讲解一下 reg1 这个正则表达式:
! 匹配一个感叹号\[ 匹配一个左中括号,因为[]在正则表达式中表示字符集,所以单独表示一个“[”符号就需要转义.+? 匹配除换行符外任意多个字符(非贪婪模式)\] 匹配一个右中括号,同上“[”符号一样,需要转义\( 匹配一个左括号,() 在正则表达式中表示分组,所以需要转义.+? 匹配除换行符外任意多个字符(非贪婪模式)\) 匹配一个右括号,同上“(”符号一样,需要转义什么是 非贪婪模式? 非贪婪模式就是尽可能少的匹配字符。在默认情况下,正则匹配都是贪婪模式匹配,也就是尽可能长的匹配字符串。类似下面这种:
const reg = /\[.+\]/
reg.exec('[123]123456]789')
// '[123]123456]'
? 在正则中本来是表示匹配0个或1个字符,但是紧跟在量词后面,? 就表示非贪婪模式,即尽可能少的匹配字符。
const reg = /\[.+?\]/
reg.exec('[123]123456]789')
// '[123]'
模版字符串用久了就会产生一种不用转义字符的错觉,是什么字符在模版字符串中就是什么样的,其实不完全是这样的,看下面这个例子
const str1 =`\w\w\w`
console.log(str1)
// 输出:www
const str2 =`\w\w\w`
console.log(str2)
// 输出:'\w\w\w'
字符串模版最终会转换为字符串,这里的 \w\w\w 会变成字符串 '\w\w\w',所以最后输出的也是 ’www‘。
所以在 RegExp 构造函数中使用字符串模版定义正则也和字符串相似,需要用\ 表示 \
当然如果不想转义序列,也可以用 String.raw() 方法
const str = String.raw`\w\w\w`
console.log(str)
// 输出:\w\w\w