Skip to content

正则要单独开一章

善用new RegExp

用它有两个好处,一是避免重复初始化regxp;二是可以以string的形式来写,斜杠等不用加反义。

匹配与groups

查询并替换 {{xxx}}

原:

const reg = /\{\{(.+)\}\}/
return str.replace(reg, (m, $1) => console.log(m, $1))
// {{aaa}} => {{aaa}} aaa
// {{aaa}}hhh{{bbb}} => {{aaa}}hhh{{bbb}} aaa}}hhh{{bbb (×)

正确:

const reg =/\{\{((?:.|\n)+?)\}\}/g

// 其实最关键的是加?啦 把贪婪模式替换为懒惰模式

默认match的内容是整个匹配项,如果只需要部分内容的话,用group

'111{{aaa}}222'.match(/{{(.+?)}}/)  
// => \["{{aaa}}", "aaa", index: 3, input: "111{{aaa}}222", groups: undefined\]  

不过此时的groups还是undefined。要显示group的内容(named captured groups),可以以?<groupName>的方式显性命名(超好用):

'111{{aaa}}222'.match(/{{(?<mustache>.+?)}}/)  
// => \["{{aaa}}", "aaa", index: 3, input: "111{{aaa}}222", groups: {mustache: "aaa"}\]  

不过,全局match有个小坑:

'111{{aaa}}222'.match(/{{(.+?)}}/g)  
// => \["{{aaa}}"\]  

可以看到此时没有单个match中额外的内容了。不过stage-4里有个新apistring.prototype.matchAll,会返回一个iterator(为什么是iterator而不就是一个数组呢,因为js期望遍历操作由用户来控制,避免无效遍历),执行后得到的值和match单个时一模一样:

\[...'111{{aaa}}222'.matchAll(/{{(.+?)}}/g)\]  
// => \[\["{{aaa}}", "aaa", index: 3, input: "111{{aaa}}222", groups: {mustache: "aaa"}\]\]  

如果在实际情况中使用,需要引入babel-polyfill或者es-shim

换行相关

  • 如何 match line breaks? Linux和新Mac use \n for a new-line; Windows \r\n and old Macs \r. 所以可以用 (\r\n|\r|\n)
  • (.+) Couldn't match 含有 line break 的 text 使用 [^.]+

转译

在处理用户输入的字符串时,一定要先转译。用MDN上的这一串简单替换就好了~

function escapeRegExp(string) {  
  return string.replace(/\[.\*+?^${}()|\[\\\]\\\\\]/g, "\\\\$&");   
  //$&表示整个被匹配的字符串  
}

Refs