正则表达式进阶技巧
正向预查
正向预查可以让我们在匹配某个模式之前,先检查是否满足某个条件。常见的正向预查有两种:
?=*
匹配后面紧跟着 *
的数字。例如:
var str = '1231231231';
var reg = /1(?=2)/g;
console.log(str.match(reg)); // ['1', '1', '1']
上面的正则表达式会匹配后面紧跟着 2
的 1
。
?!*
匹配后面没有紧跟着 *
的数字。例如:
var str = '1231231231';
var reg = /1(?!2)/g;
console.log(str.match(reg)); // ['1']
上面的正则表达式会匹配后面没有紧跟着 2
的 1
。
贪婪模式与非贪婪模式
正则表达式在匹配时,默认是贪婪模式,即只要能匹配多的就不匹配少的。例如:
var str = 'abcd{{efg}}abcd{{xzy}}';
var reg = /{{.*}}/g;
console.log(str.match(reg)); // ['{{efg}}abcd{{xzy}}']
可以看到,.
会匹配尽可能多的字符。
如果想改为非贪婪模式,只需在 *
后面加 ?
即可。例如:
var str = 'abcd{{efg}}abcd{{xzy}}';
var reg = /{{.*?}}/g;
console.log(str.match(reg)); // ['{{efg}}', '{{xzy}}']
这样就只会匹配到最少的满足条件的字符了。
非贪婪模式下,有时候会出现意想不到的结果,比如:
var str = 'aaaaaa';
var reg = /\w??/g;
console.log(str.match(reg)); // ['', '', '', '', '', '', '']
可以看到,非贪婪模式下,?
会匹配 0 次或 1 次,这里全部匹配了 0 次。
replace 方法
replace
方法可以用来替换字符串中的某些字符。但它本身不具备全局匹配的能力,只能匹配一次。例如:
var str = 'JS1231231';
var str1 = str.replace('123', '++');
console.log(str1); // JS++1231
如果想实现全局替换,需要在正则表达式上添加 g
修饰符。例如:
var str = 'JS123123';
var reg = /123/g;
var str1 = str.replace(reg, '$+');
console.log(str1); // JS$+$+
案例:将 xxyy 变成 yyxx
可以利用反向引用和重复子表达式来实现:
var str = 'aabbccdd';
var reg = /(\w)\1(\w)\2/g;
var str1 = str.replace(reg, '$2$2$1$1');
console.log(str1); // bbaaddcc
也可以使用 replace 的回调函数形式:
var str = 'aabbccdd';
var reg = /(\w)\1(\w)\2/g;
var str1 = str.replace(reg, function ($, $1, $2) {
return $2 + $2 + $1 + $1;
});
console.log(str1); // bbaaddcc
案例:将短横线命名改为驼峰命名
var str = 'js-plus-plus';
var reg = /-(\w)/g;
var str1 = str.replace(reg, function ($, $1) {
return $1.toUpperCase();
});
console.log(str1); // jsPlusPlus
案例:将驼峰命名改为下划线命名
var str = 'jsPlusPlus';
var reg = /([A-Z])/g;
var str1 = str.replace(reg, function ($, $1) {
return '_' + $1.toLowerCase();
});
console.log(str1); // js_plus_plus
案例:将 xxyyzz 变成 XxYyZz
var str = 'xxyyzz';
var reg = /(\w)\1(\w)\2(\w)\3/g;
var str1 = str.replace(reg, function ($, $1, $2, $3) {
return $1.toUpperCase() + $1 + $2.toUpperCase() + $2 + $3.toUpperCase() + $3;
});
console.log(str1); // XxYyZz
案例:将 aabbcc 变成 a$b$c$
如果想在 replace 中插入 $
符号,需要使用两个 $$
:
var str = 'aabbcc';
var reg = /(\w)\1(\w)\2(\w)\3/g;
var str1 = str.replace(reg, '$1$$$2$$$3$$');
console.log(str1); // a$b$c$
如果要插入其他特殊符号,也是类似的,在符号前面加一个 $
即可:
var str = 'aabbcc';
var reg = /(\w)\1(\w)\2(\w)\3/g;
var str1 = str.replace(reg, '$1$$*2$$*3$*');
console.log(str1); // a$*2$*3$*
转义特殊字符
在正则表达式中,有些字符有特殊含义,比如 \
、?
、+
等。如果想匹配这些字符本身,需要进行转义。例如:
var str = 'aa\\bb\\cc';
var reg = /\\/g;
console.log(str.match(reg)); // ['\\', '\\']
var str = 'aa?bb+cc';
var reg = /\?|\+/g;
console.log(str.match(reg)); // ['?', '+']
字符串去重
如果字符串中每种字符的个数都相等,可以这样去重:
var str = 'aabbcc';
var reg = /(\w)\1(\w)\2(\w)\3/g;
var str1 = str.replace(reg, '$1$2$3');
console.log(str1); // abc
如果字符个数不等,可以这样:
var str = 'aabbcc';
var reg = /(\w)\1*/g;
var str1 = str.replace(reg, '$1');
console.log(str1); // abc
给数字添加千位分隔符
// 处理整数和小数
function formatNumber(num) {
return num
.toString()
.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
.replace(/^(-?\d+)(\.\d+)?$/, function (_, int, dec) {
return int.replace(/\B(?=(\d{3})+(?!\d))/g, ',') + (dec || '');
});
}
console.log(formatNumber(1234567.89)); // 1,234,567.89
双大括号替换
var str = "My name is {{name}}. I'm {{age}} years old";
var reg = /{{(.*?)}}/g;
var str1 = str.replace(reg, function (match, key) {
return {
name: 'John',
age: 30,
}[key];
});
console.log(str1); // My name is John. I'm 30 years old
制作简单的 HTML 模板引擎
<div class="article">
<script type="text/html" id="tpl">
<div class="wrap">
<h1>{{title}}</h1>
<p>{{content}}</p>
<div>作者: {{author}}</div>
</div>
</script>
</div>
<script>
var tpl = document.getElementById('tpl').innerHTML;
var data = {
title: '标题',
content: '内容',
author: '作者',
};
var reg = /{{(.*?)}}/g;
var html = tpl.replace(reg, function (match, key) {
return data[key];
});
document.querySelector('.article').innerHTML = html;
</script>