JavaScript基础检漏之正则表达式

JavaScript基础检漏之正则表达式

前言

​ 医生的处方,道士的鬼符,程序员的正则表达式号号称普通人看不懂的三神器。可见正则表达式的地位还是蛮高的。不过相对而言,学习起来也是要花费较多精力去钻研的。

​ 当然掌握正则表达式也不一定可以写出满足任何需求的表达式,因为很多场景下,我们都是不知道”规则”的。不过掌握正则表达式后,我们可以看的懂任何的正则表达式,也足够我们吹一波了。

本片文章是作者在读《高性能JavaScript》一书第五章-字符串和正则表达式时,回头对正则表达式的使用做的一次复习~

正则表达式的定义

正则表达式由元字符和限定符组成,主要用于对字符串模式匹配及检索替换,是对字符串执行模式匹配的强大工具。

语法

var patt = new RegExp(pattern,modifiers);
var patt = /pattern/modifiers;
  • pattern(元字符) 描述了表达式的模式也是正则表达式的主体部分
  • modifiers(修饰符/限定符) 用于指定全局匹配,区分大小写的匹配和多行匹配。

修饰符

修饰符用于执行全局匹配还是不区分大小写的匹配还是多行匹配

修饰符描述
i执行对大小写不敏感的匹配。
g执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。
m执行多行匹配

/g的用法

var str = "zhouJiang(1234)zhouXue(456)",
    res = str.match(/zhou/); // 没有加/g
console.log(res); // [zhou,index:0,input:'zhouJiang(123)zhouXue(456)',groups:undefined]   只匹配一个结果
res = str.match(/zhou/g); // 加了/g开启全局匹配
console.log(res); // [zhou,zhou] 匹配到两个结果

/i的用法

var str = "zhouJiang(123)zhouXue(456)",
    res = str.match(/jiang/); // 没有加/i
console.log(res); // null 没有匹配到结果
res = str.match(/jiang/i); // 加了/i 关闭大小写的区分匹配
console.log(res); //['Jiang',index:4,input:'zhouJiang(123)zhouXue(456)',groups:undefined] 匹配到结果

/m的用法

var str = /abc/m,
    str1 = /abc/,
	res = str.test('a\nbc\nabc'),
    res1 = str1.test('a\nbc\nabc');
	console.log(res); // true 
	console.log(res1); // true

var str2 = /^abc/,
    res2 = str2.test('a\nbc\nabc');
	console.log(res2); // false;

var str3 = /^abc/m,
    res3 = str3.test('a\nbc\nabc');
	console.log(res3); // true;

var str4 = /abc$/m,
	res4 = str4.test('a\nb\nabc');
	console.log(res4); // true

拿res3来说,要检索的字符串为三行

a

bc

abc

检索要求为abc开头,第一行a开头但没有bc,继续匹配第二行bc不是a开头继续匹配第三行abc满足要求结果为true。

  • 当没有换行的时候使用/m是没有意义的。
  • 当没有^和$的时候使用/m是没有意义的。

方括号

方括号用于查找某个范围内的字符

表达式描述
[abc]查找方括号之间的任何字符。
[^abc]查找不在方括号之间的字符。
[0-9]查找0-9之间的任意数字。
[a-z]查找小写a到小写z之间的任意字符。
[A-Z]查找任何从大写A到大写Z之间的任意字符。
[A-z]查找任何从大写A到小写z的字符。匹配所有字母
[^adgk]查找给定集合外的任何字符。除adgk外的所有字符
[adgk]查找给定集合内的任何字符。包含adgk的任何字符
(red|blue|green)查找任何指定的选项。
var str = 'AabEzZ';
var res = str.match(/[A-z]/g); 
console.log(res); ['A','a','b','E','z','Z']; // 匹配所有的字母
// 换一种写法则报错
var res1 = str.match(/[a-Z]g);
console.log(res1); // 报错intimacy-real-gift-order:1129 Uncaught SyntaxError: Invalid regular expression: /[a-Z]/: Range out of order in character class

元字符

元字符描述
.查找单个字符,除了换行和行结束符。
\w查找包含下划线的单词字符。等价于[A-Za-z0-9]
\W查找非单词字符。
\d查找数字。
\D查找非数字字符。
\s查找空白字符
\S查找非空白字符。
\b匹配单词边界。
\B匹配非单词边界。
\0查找NULL字符。
\n查找换行符。
\f查找换页符。
\r查找回车符。
\t查找制表符。
\v查找垂直制表符。
\xxx查找以八进制数 xxx 规定的字符。
\xdd查找以十六进制数dd规定的字符。
\uxxxx查找以十六进制数 xxxx规定的Unicode字符。
var str = 'I will append the anwser to the dom tree';
var res = str.match(/append.{2}/ig);
console.log(res); // append t 匹配append及append后面的两个字符

常量

量词描述
n+匹配任何包含至少一个n的字符串。
n*匹配包含0个或多个的n的字符串。
n?匹配的包含0个或一个的n的字符串。
n{X}匹配连续的包含x个的n的字符串。
n{X,}匹配连续的包含至少X个的n的字符串。
n{X,Y}匹配连续的包含X到Y个的n的字符串。
n$匹配任何结尾为n的字符串。
^n匹配任何以n开头的字符串。
?=n匹配任何其后紧接指定字符串n的字符串。返回结果不包含n
?!n匹配任何其后没有紧接指定字符串n的字符串。返回结果不包含n
// 找出阅读量的数字  ?= 零宽正向先行断言
var str = `<div><span class='read-count'>阅读数:641</span>vfdsjfdsf</div>`;
var reg = /\d+(?=<\/span>)/g;
console.log(str.match(reg)); // ["641"]

// ?<= 找出span中的数值 零宽后行断言
var str1 = 'a123s33333aaa444s';
var reg = /(?<=s)\d+/g; 
console.log(str1.match(reg)); // ['33333'];

var str = "<p>Para 1.</p>" + 
		"<img src='smiley.jpg'>" +
		"<p>Para 2.</p>" + 
		"<div>Div.</div>";
var reg = /(?<=<p>).*?(?=<\/p>)+/ig;
console.log(str.match(reg)); // ["Para 1.", "Para 2."]

贪婪模式和非贪婪模式

正则表达式默认都是采用的贪婪模式,要取消贪婪模式时,我们需要添加?来取消贪婪模式。

var str = "<div><img src='1.jpg' /><img src='2.jpg' /></div>";
var reg = /<img.+\/>/g;
console.log(str.match(reg)); // ["<img src='1.jpg' /><img src='2.jpg' />"]

// 关闭贪婪模式
var reg1 = /<img.+?\/>/g;
console.log(str.match(reg1)); // ["<img src='1.jpg' />", "<img src='2.jpg' />"]

小括号引用

小括号除了对特定的组合进行分组外,还具有一个定义子正则。

当正则较为复杂时,我们或许就需要小括号来引用子正则。

用法一:引用方法为\数字

\1的意思就是引用第一个()内的正则,\2的意思为引用第二个()的正则。

/(['"])(.+?)\1/g == /['"](.+?)\1/g;

这里\1的意思其实就是[‘“];

用法二:可以通过$数字来获取对应小括号的值

$1就是第一个小括号中对应匹配的值,$2就是第二个小括号中对应匹配的值。

一码顶前言:匹配出字符串中的图片路径

var htmlStr = `<div><img src="https://static.bgwhite.cn/react-website/gwc_hd.jpeg" title="张三" />这里是一段文字信息。<img src="https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3724469498,1550122559&fm=26&gp=0.jpg" />sfdsfdsafdsafdsafdsf	
</div>`;
var regImgTag = /<img src=(['"]?)([^'"]*?)\1[^>]*?>/ig;
var imgTagArr = htmlStr.match(regImgTag); // 所有的图片标签
console.log('img标签集合:',imgTagArr);
for (var i = 0,len = imgTagArr.length;i<len;i++) {
	let imgSrc = imgTagArr[i].replace(regImgTag,'$2')
	console.log('487', imgSrc);
}

reg1.png

上述代码中\1其实就是第一个小括号中的子正则['"]?

$2匹配的就是[^'"]*?

关闭分组

var pattern = /(ab)123(ba)/;
console.log('ab123ba_'.replace(pattern,'$1')); // ab_
console.log('ab123ba_'.replace(pattern,'$2')); // ba_

var pattern1 = /(?:ab)123(ba)/;
console.log('ab123ba_'.replace(pattern1,'$1')); // ba_

此时,在添加括号时,将不会产生分组。使用$1将查询不到这里的数据。

断言

字符描述
(?=pattern)正向先行断言,紧接该位置之后的字符序列能够匹配pattern
(?!pattern)负向先行断言,紧接该位置之后的字符序列不能匹配pattern
(?<=pattern)正向后行断言,紧接该位置之前的字符序列能够匹配pattern
(?<!pattern)负向后行断言,紧接该位置之前的字符序列不能匹配pattern

JavaScript暂不支持负向后行断言。

replace替换字符

字符替换文本
$1,$2,….,$99与reg中的第1到底99个匹配到的子表达式。
$&与reg中相匹配的所有子串。
$`位于匹配子串左侧的文本。
$’位于匹配子串右侧的文本。
$$直接量符号。
var str = '1a2b3c4d56789';
console.log(str.replace(/(\d+)/g,'$&,')); // 1,a2,b3,c4,d56789,

RegExp对象方法

方法描述
exec检索字符串中指定的值。返回找到的值,并确定其位置
test检索字符串中指定的值。返回true或false。
toString返回正则表达式的字符串。

支持正则表达式的String对象的方法

方法描述
search检索于正则表达式相匹配的值。
match找到一个或多个正则表达式的匹配。
replace替换于正则表达式匹配的子串。
split把字符串分割为字符串数组。

常用正则表达式累积

手机号

/^1[3-9]\d{9}$/g // 1开头,第二位是3-9的任意数字,然后拼接任意的9个数字

固定电话

/^(\(\d{3,4}\)|\d{3,4}-|\s)?\d{7,14}$/

正整数

/^\+?[1-9][0-9]*$/g //转义加号,以加号开头0个或1个,接上1-9的任意数字,在加上0-9的任意数字0个或多个

只能输入数字

this.value = this.value.replace(/[^\d]/g,'');

保留两位小数的价格

/^\+?[1-9]+\.[0-9]{2}$/g;

金额千分位转换

var f = '99999999999.02'.replace(/\d{1,3}(?=(\d{3})+(?:\.\d{1,2})?$)/g, '$&,');
console.log(f); //99,999,999,999.02

邮箱

/^[\dA-z]+([\-\.\_]?[\da-z]+)*@[\da-z]+([\-\.]?[\da-z]+)*(\.[a-z]{2,})+$/i

身份证

/^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/

护照

/(^[EeKkGgDdSsPpHh]\d{8}$)|(^(([Ee][a-fA-F])|([DdSsPp][Ee])|([Kk][Jj])|([Mm][Aa])|(1[45]))\d{7}$)/

网址

/(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/g)

必须带端口号的网址/IP

/^((ht|f)tps?:\/\/)?[\w-]+(\.[\w-]+)+:\d{1,5}\/?$/

匹配html字符串中的图片路径

var htmlStr = `<div><img src="https://static.bgwhite.cn/react-website/gwc_hd.jpeg" title="张三" />这里是一段文字信息。<img src="https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3724469498,1550122559&fm=26&gp=0.jpg" />sfdsfdsafdsafdsafdsf	
</div>`;
var regImgTag = /<img src=(['"]?)([^'"]*?)\1[^>]*?>/ig;
var imgTagArr = htmlStr.match(regImgTag); // 所有的图片标签
for (var i = 0,len = imgTagArr.length;i<len;i++) {
	let imgSrc = imgTagArr[i].replace(regImgTag,'$2')
	console.log('487', imgSrc);
}

检测输入是否为空

var reg = /\S/;
if (!reg.test(str)) {
    console.log('文本框不能为空,请输入内容');
}

火车车次

/^[GCDZTSPKXLY1-9]\d{1,4}$/

手机机身码

/^\d{15,17}$/

统一社会信用代码

/^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$/

迅雷链接

/^thunderx?:\/\/[a-zA-Z\d]+=$/

子网掩码

/^(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])(?:\.(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])){3}$/

md5格式(32位)

/^([a-f\d]{32}|[A-F\d]{32})$/

视频地址

/^https?:\/\/(.+\/)+.+(\.(swf|avi|flv|mpg|rm|mov|wav|asf|3gp|mkv|rmvb|mp4))$/i

图片地址

/^https?:\/\/(.+\/)+.+(\.(gif|png|jpg|jpeg|webp|svg|psd|bmp|tif))$/i

base64格式

/^\s*data:(?:[a-z]+\/[a-z0-9-+.]+(?:;[a-z-]+=[a-z0-9-]+)?)?(?:;base64)?,([a-z0-9!$&',()*+;=\-._~:@/?%\s]*?)\s*$/i

银行卡号

/^[1-9]\d{9,29}$/

中文姓名

/^(?:[\u4e00-\u9fa5·]{2,16})$/

英文姓名

/(^[a-zA-Z]{1}[a-zA-Z\s]{0,20}[a-zA-Z]{1}$)/

车牌号(新能源)

/[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领 A-Z]{1}[A-HJ-NP-Z]{1}(([0-9]{5}[DF])|([DF][A-HJ-NP-Z0-9][0-9]{4}))$/

车牌号(非新能源)

/^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领 A-Z]{1}[A-HJ-NP-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$/

qq号

/^[1-9][0-9]{4,10}$/

密码强度检测

最少6位,包括至少1个大写字母,1个小写字母,1个数字,1个特殊字符

/^\S*(?=\S{6,})(?=\S*\d)(?=\S*[A-Z])(?=\S*[a-z])(?=\S*[!@#$%^&*? ])\S*$/

16进制颜色

/^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/

邮政编码

/^(0[1-7]|1[0-356]|2[0-7]|3[0-6]|4[0-7]|5[1-7]|6[1-7]|7[0-5]|8[013-6])\d{4}$/

注:部分内容参考:https://juejin.cn/post/6844904182835757064


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!