Skip to content

正则表达式总结 #2

Description

@Bjkb

自己对正则表达式的使用,还停留在校验手机号、身份证这种级别,趁着中秋假期,梳理一波正则表达式的使用。

正则表达式基础

这里列举一些基本的,完整的查看正则表达式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;
}

结语

通过这一次的正则做题,让自己对正则有了一个清晰的认识,也巩固了以往正则的基础,收获非常大。

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions