阅读 395

前端学习笔记-正则表达式

相关符号的含义

图片总结

image.png

image.png

正则表达式的组成

let reg = /pattern/flags;
复制代码

其中pattern(模式)是正则表达式的主体。flags(标记),用于控制正则表达式的行为。flags的取值有以下几种

  • g:全局模式,表示查找字符串的全部内容,而不是找到第一个匹配的内容就结束。
  • i:不区分大小写,表示在查找匹配时忽略pattern和字符串的大小写。
  • m:多行模式,表示查找到一行文本末尾时会继续查找。
  • y:粘附模式,表示只查找从1astIndex开始及之后的字符串。
  • u:Unicode模式,启用Unicode匹配。
  • s:dotA11模式,表示元字符.匹配任何字符(包括\n或\r)。

从这里可以看出,前边图中说元字符.匹配除换行符之外的任何字符是不准确的。如果加上s标志,则可以匹配任意字符

元字符

元字符共有14个,在使用的时候需要加上\进行转义 {}[]()^$\|?*+.

中括号[]

  • [-.]表示符号-或者.号(注意这里,在[]中的.号代表的就是这个符号,但是如果在其外面,表示个匹配所有。 所以如果不在[]之中,想要匹配'.',就要通过转意符号.)
  • []中,特殊字符不需要转义,可以直接使用,比如[.()],但是在外面,是需要转义的( .等
  • []中的^标识非,[]外的^标识开头标识
  • [abc]表示a或者b或者才,但/abc/表示连续的abc字符
  • 在分组中表示或的方式(a|b),a或者b,对应[ab]
  • []中需要进行转义的字符有[]^-,其他的元字符不需要转义即可使用

关于\b

可参考 正则表达式之 \b

  • \b 匹配这样的位置:它的前一个字符和后一个字符不全是(一个是,一个不是或不存在) \w。
  • 换一种说法就是:它的前一个“显式位置”字符和后一个“显式位置”字符不全是 \w。

RegExp和String相关的正则操作

test

  • 属于正则的方法,判断一个字符串是否符合正则表达式的约束
  • 用法如reg.test(str)返回值只可能是false或者true

exec

  • 属于正则的方法,找出字符串中符合该正则的片段
  • 用法如reg.exec(str)返回一个数组,数组的长度大于等于1,第一项是匹配的片段,如果正则里有分组(),则该数组从第二项依次是是1,1,2,...分组匹配到的内容
const str = '1234';
const reg1 = /\d{1}(\d{1})/g;//带有g表示匹配字符串中的所有片段
console.log(reg1.exec(str));//["12", "2", index: 0, input: "1234", groups: undefined]
console.log(reg1.exec(str));//["34", "4", index: 2, input: "1234", groups: undefined]
console.log(reg1.exec(str));//null

const reg2 = /\d{1}(\d{1})/;//不带g,表示匹配到第一个满足的片段,就不再继续匹配
console.log(reg2.exec(str));//["12", "2", index: 0, input: "1234", groups: undefined]
console.log(reg2.exec(str));//["12", "2", index: 0, input: "1234", groups: undefined]
复制代码

需要注意带有标识g和不带标识g,exec会有不一样的特性

match

  • 属于字符串的方法,找出字符串中符合该正则的片段,和exec类似
  • 用法如str.match(reg)返回一个数组,需要注意g标识的区别
const str = '1234';
const reg1 = /\d{1}(\d{1})/g;
const reg2 = /\d{1}(\d{1})/;
console.log(str.match(reg1));//["12", "34"]
console.log(str.match(reg2));//["12", "2", index: 0, input: "1234", groups: undefined]
复制代码

replace

  • 属于字符串的方法,对字符串中正则匹配到的片段进行替换操作
  • 用法如str.repalce(reg, param)返回一个新的字符串。param第二个参数可以是一个字符串,或者一个返回替换内容的函数。

split

  • 属于字符串的方法,按照一个正则表达式的匹配,将字符串拆分为数组
  • 用法如str.split(param)返回一个数组。param第二个参数可以是一个字符串,或者一个正则表达式。

关于replace的匹配细节

const str = '1335555666617788884444';
const reg1 = /(?<=\d{3})\d{4}(?=\d{4})/g;
const reg2 = /(?<=\d{3})\d{4}(?=\d{4})/;
console.log(str.match(reg1));//"["5555", "6666", "1778"]"
console.log(str.replace(reg1,'****'));//"133************8884444"
console.log(str.replace(reg2,'****'));//"133****666617788884444"
复制代码

replace要替换的内容,和str.match(reg)匹配到的内容是对应的。而str.match(reg)reg.exec(str)效果又是相似的。

可以从以下例子看出匹配过程

const str = '1335555666617788884444';
const reg1 = /(?<=\d{3})\d{4}(?=\d{4})/g;
let match;
console.log(reg1.lastIndex);//0
while(match !== null){
    match = reg1.exec(str);
    //每次进行一个exec,reg1的lastIndex会响应的增加,
    //增加的值等于,匹配到的字符的位置+匹配字符的长度
    console.log(match);//会打印出每次exec的匹配项
    console.log(match && match.index, reg1.lastIndex);
    //macth是匹配项在目标字符串str中的索引值
    //reg1.lastIndex表示下一次匹配将从这个索引值的位置开始
}
复制代码

打印结果如下

image.png

由此可以得出结论。

  • 1335555666617788884444最先被匹配到的内容是5555,字符串被替换为133****666617788884444这时,reg的lastIndex值不再为0,变为7,下一次匹配会从索引值为7的位置继续匹配。
  • 匹配到6666,替换为****,reg的lastIndex值变为11;匹配到1778,reg的lastIndex值变为15;后面的内容8884444不再满足匹配规则,匹配完毕,reg的lastIndex值变为0

关于贪婪和惰性

字符串1234/\d{1,3}/g/\d{1,3}?/g匹配,会有不一样的结果

const str = '1234';
const reg1 = /\d{1,3}/g;
const reg2 = /\d{1,3}?/g;
console.log(str.match(reg1));//["123","4"]
console.log(str.match(reg2));//["1","2","3","4"]
复制代码

没有加惰性符号?时,匹配默认是贪婪的,\d{1,3}匹配长度为1-3的数字,贪婪的匹配时没回都按最多的来,所以会有"123",加了?代表惰性匹配,按最少的来,所以会是"1"

再比如,我们要匹配一个标签中的href链接的话,则运用惰性标识?会很有用

const str = '<a href="https://www.baidu.com" id="cscs" title="一个链接">测试文字</a>';
const reg1 = /".+"/g;
const reg2 = /".+?"/g;
console.log(str.match(reg1));//只匹配到1项
//["\"https://www.baidu.com\" id=\"cscs\" title=\"一个链接\""]

console.log(str.match(reg2));//匹配到3项
//["\"https://www.baidu.com\"", "\"cscs\"", "\"一个链接\""]
复制代码

几种代表性的正则写法

金额类数字,划分

将一个金额11222333444转为11,222,333,444的形式;

const str = '111333222';
const reg1 = /(\d{1,3})(?=(\d{3})+$)/g;
const reg2 = /(\d)(?=(\d{3})+$)/g;
const reg3 = /(?<=\d)(?=(\d{3})+$)/g;
const str2 = str.replace(reg1, '$1,');
const str3 = str.replace(reg3, ',');
const str4 = str.replace(reg2, '$1,');
const str5 = str.replace(reg1, function(match){
    return match+',';
});
console.log(str.match(reg1));//["11", "222", "333"]
console.log(str.match(reg2));// ["1", "2", "3"]
console.log(str.match(reg3));//["", "", ""]
console.log(str2);//11,222,333,444
console.log(str3);//11,222,333,444
console.log(str4);//11,222,333,444
console.log(str5);//11,222,333,444
复制代码
  • 需要注意两种RegExp匹配到的内容是不同的,通过reg3可以看出,正则可以直接匹配到字符串之间的空白
  • reg3如果是/(?=(\d{3})+$)/g则会存在缺陷,因为
'111222333'.replace(/(?=(\d{3})+$)/g, ',');//,111,222,333
复制代码

所以需要对前边的字符进行限制

  • 另外number有toLocaleString方法,可以直接做这样的转换

下划线转驼峰命名

const str = 'get_my_color';
const str2 = str.replace(/_([a-z])/g, (item, $1) => $1.toUpperCase());
console.log(str2);
复制代码

电话号码隐藏中间4位

const str = '13311112222';
const str2 = str.replace(/(\d{3})(\d{4})(\d{4})/, '$1****$3');
const str3 = str.replace(/(\d{3})(?:\d{4})(\d{4})/, '$1****$2');
const str4 = str.replace(/(?<=\d{3})\d{4}(?=\d{4})/, '****');
console.log(str2);//133****2222
console.log(str3);//133****2222
console.log(str4);//133****2222
复制代码

str2和str4匹配到的内容是不同的

判断一个字符串中出现次数最多的字符,并统计次数

这里是对分组的应用例子

const str = 'aaabbbcccaaabbbaaa';
const str2 = str.split('').sort().join('');  //"aaaaaaaaabbbbbbccc"
const arr = str2.match(/(\w)\1+/g);//对\1的应用
arr.sort(function(a,b) {
    return b.length - a.length;
});//按从大到小排序
console.log(arr);//["aaaaaaaaa", "bbbbbb", "ccc"]
console.log(arr[0]);//aaaaaaaaa
复制代码

字符串中空白插入指定字符

将qwer转为qwer*

const str = 'qwer';
const reg1 = new RegExp('', 'g');
const reg2 = /(?:)/g;
console.log(str.replace(reg1, '*'));//*q*w*e*r*
console.log(str.replace(reg2, '*'));//*q*w*e*r*
复制代码

直接写//g匹配空字符是无效的

找出链接中的文件后缀名

const str = 'https://pic2.zhimg.com/v2-5f03165aa5dff60d75c0f49f0ddd3db3_is.jpg?hhyr';
const reg1 = /(\.[A-z0-9]+$)|(\.[A-z0-9]+(?=\?\w+$))/;
const reg2 = /\.([A-z0-9]+)(\?\w*)?$/;
console.log(str.match(reg1)[0]);//.jpg
console.log(str.match(reg2)[1]);//jpg
复制代码

13提取Object.prototype.toString.call的类型

let a = new WeakMap();
function getType(o) {
    let str = Object.prototype.toString.call(o);
    let reg = /\b\w+(?=\]$)/;
    return str.match(reg)[0];
}
console.log(getType(a));//WeakMap
复制代码

常用的正则整理

/[1-9]\d*/;//正整数
/-[1-9]\d*/;//负整数
/(-?[1-9]\d*)|0/;整数(正整数、负整数和0)
/[\u4e00-\u9fa5]/;中文字符
复制代码

其他的待整理

正则在线测试工具菜鸟工具

参考可能是最好的正则表达式的教程笔记了吧...

文章分类
前端
文章标签