解密正则表达式:巧妙处理手机号脱敏、文字高亮的秘籍

介绍了正则的断言、原子组、嵌套分组与不记录组、模式修正符等,举例了使用正则进行手机号脱敏、网址匹配、文字替换、文字高亮显示的处理

1. 手机号脱敏,模糊手机号

为了安全考虑,一般前端显示时,会将手机号中间 4 位加密,即17777777777 -> 177****7777

正则断言

  • ?=:正向先行断言,当前位置之后的字符序列能匹配pattern(后置断言,后面是 xx)
  • ?!:负向先行断言,当前位置之后的字符序列不能匹配pattern(后置断言,后面不是 xx)
  • ?<=:正向后行断言,当前位置之前的字符序列能匹配 pattern(前置断言,前面是 xx)
  • ?<!:负向后行断言,当前位置之前的字符序列不能匹配 pattern(前置断言,前面不是 xx)
js 复制代码
// 1. 获取数字后的字符串:以字符结尾,后面不是数字的字符串
let str = "abcdefg2023com";

let reg = /[a-z]+(?!\d+)$/i;
console.log(str.match(reg)); // 获取com

// 2. 前面不是数字的断言
console.log(str.match(/(?<!\d+)[a-z]+/i)); // 获取abcdefg

1.1 正则断言+replace

  1. (?<=\d{3}):正向后行断言,表示匹配当前位置之前的三个数字
  2. \d{4}:表示当前位置匹配的是四个数字
  3. (?=\d{4}):正向先行断言,表示匹配当前位置之后的四个数字
  4. gi:g 表示全局匹配(即找到所有匹配项),i 表示不区分大小写。
js 复制代码
let reg = /(?<=\d{3})\d{4}(?=\d{4})/gi;
let phone = "17777777777";
phone = phone.replace(reg, (v) => {
  console.log(v); // 7777
  return "*".repeat(4);
});
console.log(phone); // 177****7777

1.2 substr 切片

js 复制代码
let phone = "17777777777";
phone = phone.substr(0, 3) + "****" + phone.substr(7);
console.log(phone);

原子组

原子组:使用()匹配并捕获的内容,从左往右数个数,代表序号

给原子组起别名 ?<xx>

js 复制代码
let str = `
    <h1>hello</h1>
    <h2>world</h2>
    `;

// 原子组:\1 \2 \3等等
// (h[1-6])为\1
// ([\s\S]*)为\2
let reg1 = /<(h[1-6])>([\s\S]*)<\/\1>/i;
console.dir(str.match(reg1));

// 给原子组起别名 ?<xx>
let reg2 = /<(?<str1>h[1-6])>(?<str2>[\s\S]*)<\/\1>/i;
console.dir(str.match(reg2));

let reg3 = /<(h[1-6])>([\s\S]*)<\/\1>/gi;
console.dir(str.match(reg3));
js 复制代码
// 将h1,h2标签替换为p标签
let result = str.replace(reg3, (p0, p1, p2) => {
  // p0代表整体匹配元素
  console.log(p0);
  // p1代表原子组1匹配元素
  console.log(p1);
  // p2代表原子组2匹配元素
  console.log(p2);

  return `<p>${p2}</p>`;
});
console.log(result);

// 此处$2就代表原子组2匹配到的值
console.log(str.replace(reg3, `<p>$2</p>`));

嵌套分组与不记录组

js 复制代码
// 网址中取域名
let str = `
    https://www.baidu.com
    http://cdn.baidu.com
    https://baidu.com
    `;

// 1. 原子组从左边开始算括号
// ((\w+\.)+(com|cn))为\1,匹配www.baidu.com
// (\w+\.)为\2,匹配baidu.
// (com|cn)为\3,匹配com
let reg1 = /https?:\/\/((\w+\.)+(com|cn))/i;
console.dir(str.match(reg1));

// 2. 如果想忽略某个原子组,需要加上?:
let reg2 = /https?:\/\/((?:\w+\.)+(?:com|cn))/i;
console.dir(str.match(reg2));

// 3. 获取域名地址数据 全局匹配
let reg3 = /https?:\/\/((?:\w+\.)+(?:com|cn))/gi;
console.dir(str.match(reg3));
let result = [];
let res = [];
while ((res = reg3.exec(str))) {
  result.push(res[1]);
}
console.log(result);

1.3 正则分组+replace

  1. (\d{3}):匹配并捕获三个数字 第一个原子组,对应$1
  2. \d{4}:匹配四个数字
  3. (\d{4}):匹配并捕获四个数字 第二个原子组,对应$2
js 复制代码
let phone = "17777777777";
let reg = /(\d{3})\d{4}(\d{4})/;
// 方式一:
let phone1 = phone.replace(reg, "$1****$2");
console.log(phone1);

// 方式二:
let phone2 = phone.replace(reg, (p0, p1, p2) => {
  console.log(p0, p1, p2); // 17777777777 177 7777
  return p1 + "*".repeat(4) + p2;
});
console.log(phone2);

2. 文字替换

模式修正符

  • g:全局匹配,找到所有匹配;不加时,匹配到一个就停了
    • gu:全局匹配且启用 Unicode 模式
    • gi:全局匹配且不分大小写
    • gs:全局匹配且让 . 包括换行符
  • i:不区分大小写
  • u:启用 Unicode 匹配模式
  • s:让特殊字符圆点 . 中包含换行符 \n(可以让多行转换成单行)
  • m:多行匹配修正符(每一行单独处理,^ 和 $ 匹配每一行的开始和结束)
  • y:粘性匹配,从目标字符串的当前位置开始匹配(连续一直匹配,没匹配上就停止)
js 复制代码
// 单行处理(m 多行匹配修正符)
let str = `
          #1 js,200元 #
          #2 php,300元 #
          #3 nodejs,180元 #
        `;
let result = str.match(/^\s*#\d+\s+.+\s+#$/gm).map((v) => {
  console.log(v);
  v = v.replace(/\s*#\d+\s*/, "").replace(/\s+#/, "");
  [name, price] = v.split(",");
  return { name, price };
});
console.dir(result);

2.1 文字高亮显示

js 复制代码
// 文字高亮显示
let str = "www.baidu.com";
let result = str.replace(/baidu/g, (search) => {
  return `<span style="color: red;">${search}</span>`;
});
// www.<span style="color: red;">baidu</span>.com
console.log(result);

2.2 新闻 rem 替换

正常页面中,375*667 手机中,配置的 1rem=100px

引入了一个新闻页,它在 375*667 手机中,适配的 1rem=18.75px

为了保证 rem 适配一致,需要进行全局替换

js 复制代码
const content = `<p
  class="formatted"
  style="text-align:justify;line-height:1.875rem;margin-bottom:1.875rem;font-size:1.1875rem"
>
  新闻记者 哈哈哈
</p>`;

const result = content.replace(/(\d*\.?\d+)rem/g, (match, number) => {
  // console.log(match, number);
  // 字体设置为18.75px,字体样式设置为1.1875rem,故字体大小为18.75*1.1875=22px
  return ((parseFloat(number) * 375) / 2000).toFixed(2) + "rem";
});
console.log(result);
相关推荐
昙鱼6 分钟前
springboot创建web项目
java·前端·spring boot·后端·spring·maven
天天进步201512 分钟前
Vue项目重构实践:如何构建可维护的企业级应用
前端·vue.js·重构
小华同学ai15 分钟前
vue-office:Star 4.2k,款支持多种Office文件预览的Vue组件库,一站式Office文件预览方案,真心不错
前端·javascript·vue.js·开源·github·office
APP 肖提莫16 分钟前
MyBatis-Plus分页拦截器,源码的重构(重构total总数的计算逻辑)
java·前端·算法
问道飞鱼27 分钟前
【前端知识】强大的js动画组件anime.js
开发语言·前端·javascript·anime.js
k093329 分钟前
vue中proxy代理配置(测试一)
前端·javascript·vue.js
傻小胖30 分钟前
React 脚手架使用指南
前端·react.js·前端框架
程序员海军43 分钟前
2024 Nuxt3 年度生态总结
前端·nuxt.js
m0_748256781 小时前
SpringBoot 依赖之Spring Web
前端·spring boot·spring
web135085886351 小时前
前端node.js
前端·node.js·vim