自己对正则表达式的使用,还停留在校验手机号、身份证这种级别,趁着中秋假期,梳理一波正则表达式的使用。
正则表达式基础
这里列举一些基本的,完整的查看正则表达式MDN
| 字符 |
含义 |
| \ |
表示下一个字符不是特殊字符,常用来做转义 |
| ^ |
表示以什么开头,必须要在开头的位置才行,eating,用这个匹配 a 肯定没效果 |
| $ |
表示以什么结尾,必须要在结尾的位置才行,跟上面同理 |
| . |
表示换行符之外的任意单个字符 |
| * |
表示匹配 0 - 多次,类似 {0,} |
| + |
表示匹配 1- 多次,类似{1,} |
| ? |
表示匹配 0-1次,类似{0,1} |
| (x) |
会记住匹配项 x |
| (?:x) |
不会记住匹配项x |
| x(?=y) |
匹配x,只有当x后面是y的时候,先行断言 |
| (?<=y)x |
匹配x,只有当x前面是y的时候,后行断言 |
| x(?!y) |
匹配x,只有当x后面不是y的时候,正向否定查找 |
| (?<!y)x |
匹配x,只有当x前面不是y的时候,反向否定查找 |
| x|y |
匹配x或者y |
常见的正则表达式题目
通过这些题目,对使用正则做一个综合性的测试
题目来源:
手写题:9道字符串类高频面试题(掘金)
解析URL params为对象
var url = 'http://www.domain.com/?user=anonymous&id=123&id=456&city=%E5%8C%97%E4%BA%AC&enabled';
parseParam(url)
/* 结果
{ user: 'anonymous',
id: [ 123, 456 ], // 重复出现的 key 要组装成数组,能被转成数字的就转成数字类型
city: '北京', // 中文需解码
enabled: true, // 未指定值得 key 约定为 true
}
*/
解法:
function parseParam(url){
let obj = {};
if(!url) return obj;
let searchParams = url.match(/(?<=\?).*/g)[0]; // 匹配 ?号之后的内容
searchParams.split('&').forEach((item)=>{
let [key, value ] = item.split('=');
if(value){
value = /^\d+$/.test(value)?parseFloat(value): decodeURIComponent(value); // 判断是否是数字以及解码
}else{
value = true
}
if(obj[key]){ // 判断是否已经存在了这个key,存在就得推入数组里
obj[key] = Array.isArray(obj[key])? obj[key].push(value): obj[key] = [obj[key],value];
return;
}
obj[key] = value;
})
return obj;
}
实现一个编译模板
let template = '我是{{name}},年龄{{age}},性别{{sex}}';
let data = {
name: '姓名',
age: 18
}
compile(template, data); // 我是姓名,年龄18,性别undefined
解法一:
// 正则替换{{}}里面的内容
function compile(template,data){
return template.replace(/{{\w+}}/g,item=>data[item.match(/\w+/)]);
}
上面的方法有个问题是,只能替换简单key,复杂一点的,比如 {{obj.name}},就GG了
题目有个变种:
let template = compile(template);
template({name:'姓名',age:18});
// 可以将字符串写成字符串表达式,类似下面这样
let template = '我是'+obj.name+',年龄'+obj.age+',性别'+obj.sex+'';
解法二:
// 要使用这种方式,得借助一下 new Function(),创建一个新的函数
function compile(template){
// 将 template 替换成 '我是'+obj.name+',年龄'+obj.age+',性别'+obj.sex+'';
let str = template.replace(/{{\w+}}/g,item=>`'+obj.${item.match(/\w+/)}+'`);
let newFn = new Function('obj',`return '${str}'`); // 第一个参数,第二个 return 返回值
/*
function anonymous(obj){
return '我是'+obj.name+',年龄'+obj.age+',性别'+obj.sex+'';
}
*/
return newFn;
}
转化为驼峰命名
let str = "get-element-by-id"
// 转化为 getElementById
解法:
// 匹配 -跟后面的单个字符,再利用 replace 替换掉
str = str.replace(/-\w/g,x=>x.slice(1).toUpperCase())
查找字符串中出现最多的字符跟次数
例: abbcccddddd -> 字符最多的是d,出现了5次
let str = "abcabcabcbbccccc";
let num = 0;
let char = '';
// 使其按照一定的次序排列
str = str.split('').sort().join('');
// "aaabbbbbcccccccc"
// 定义正则表达式
let re = /(\w)\1+/g; // 匹配单字符,并记住它
replace具体方法参数可以参考 String.prototype.replace
| 参数 |
含义 |
| match |
匹配的子串 |
| p1,p2,... |
匹配括号中的内容,依次推 |
| offset |
偏移量 |
| string |
原字符串 |
str.replace(re,(match,p1) => {
if(num < match.length){
num = match.length;
char = p1;
}
});
console.log(`字符最多的是${char},出现了${num}次`);
字符串查找
a='34';b='1234567'; // 返回 2
a='35';b='1234567'; // 返回 -1
a='355';b='12354355'; // 返回 5
isInclude(a,b);
function isInclude(a,b){
const result = b.match(new RegExp(a));
return result === null ? -1 : result.index;
}
实现千位分隔符
parseToMoney(123456789); // return '123,456,789'
function parseToMoney(num){
let str = '';
let [integer,decimal] = String.prototype.split.call(num,'.');
str = integer.replace(/(?<=\d)(?=(\d{3})+$)/g,','); // 以数字开头,3个数字为一组,匹配多次
return decimal?str+'.'+decimal:str;
}
结语
通过这一次的正则做题,让自己对正则有了一个清晰的认识,也巩固了以往正则的基础,收获非常大。
正则表达式基础
这里列举一些基本的,完整的查看正则表达式MDN
常见的正则表达式题目
解析URL params为对象
实现一个编译模板
转化为驼峰命名
查找字符串中出现最多的字符跟次数
replace具体方法参数可以参考 String.prototype.replace
字符串查找
实现千位分隔符
结语
通过这一次的正则做题,让自己对正则有了一个清晰的认识,也巩固了以往正则的基础,收获非常大。