正则表达式剖析-案例
一直都是在用正则表达式,没有好好的汇总过。正好,遇到很多小算法,可以作为案例补充。 正则表达式的定义:正则表达式是由普通字符和特殊字符(也叫元字符或限定符)组成的文字模板。 元字符: . 匹配除换行符(nr)以外的任意字符
d 匹配数字,等价于字符组[0-9]
w 匹配字母,数字,下划线或汉字
s 匹配任意的空白符(包括制表符,空格,换行等)
b 匹配单词开始或结束的位置
^ 匹配行首
$ 匹配行尾
反义元字符 D 匹配非数字的任意字符,等价于[^0-9]
W 匹配除字母,下划线或汉字之外的任意字符
S 匹配非空白的任意字符
B 匹配非单词开始或结束的位置
[^x]匹配除x以外的任意字符
重复限定符: 限定符共有6个,假设重复次数为x次,那么将有如下规则: * x>=0
+ x>=1
? x=0 or x=1
{n} x=n
{n,} x>=n
{n,m} n<=x<=m
字符组
排除性字符组
多选结构
括号
转义字符
操作符的运算优先级1、转义符
2、(),(?:),(?=),[] 圆括号或方括号
3、*,+,?,{n},{n,},m} 限定符
4、^,$ 位置
5、| "或" 操作
修饰符javaScript中正则表达式默认有如下五种修饰符:
g (全文查找) i (忽略大小写查找) m (多行查找) y (ES6新增的粘连修饰符) u (ES6新增)
常用的正则表达式 汉字: ^[u4e00-u9fa5]{0,}$ Email: ^w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*$ URL: ^https?://([w-]+.)+[w-]+(/[w-./?%&=]*)?$ 手机号码: ^1d{10}$ 身份证号: ^(d{15}|d{17}(d|X))$ 中国邮政编码: [1-9]d{5}(?!d) (邮政编码为6位数字)
密码验证
var reg = /(?!^[0-9]+$)(?!^[A-z]+$)(?!^[^A-z0-9]+$)^[^su4e00-u9fa5]{6,16}$/;
贪婪模式与非贪婪模式默认情况下,所有的限定词都是贪婪模式,表示尽可能多的去捕获字符; 而在限定词后增加?,则是非贪婪模式,表示尽可能少的去捕获字符. 如下: var str = "aaab",reg1 = /a+/,//贪婪模式
reg2 = /a+?/;//非贪婪模式
console.log(str.match(reg1)); //["aaa"],由于是贪婪模式,捕获了所有的a
console.log(str.match(reg2)); //["a"],由于是非贪婪模式,只捕获到第一个a
实际上,非贪婪模式非常有效,特别是当匹配html标签时. 比如匹配一个配对出现的div,方案一可能会匹配到很多的div标签对,而方案二则只会匹配一个div标签对. var str = "<div class='v1'><div class='v2'>test</div><input type='text'/></div>"; var reg1 = /<div.*</div>/; //方案一,贪婪匹配 var reg2 = /<div.*?</div>/;//方案二,非贪婪匹配 console.log(str.match(reg1));//"<div class='v1'><div class='v2'>test</div><input type='text'/></div>" console.log(str.match(reg2));//"<div class='v1'><div class='v2'>test</div>"
区间量词的非贪婪模式
区间量词”{n,m}” 也是匹配优先,虽有匹配次数上限,但是在到达上限之前,它依然是尽可能多的匹配,而 “{n,m}?” 则表示在区间范围内,尽可能少的匹配. 需要注意的是: 能达到同样匹配结果的贪婪与非贪婪模式,通常是贪婪模式的匹配效率较高. 分组
如下,小括号内包裹的abc便是一个分组: /(abc)+/.test("abc123") == true
那么分组有什么用呢? 一般来说,分组是为了方便的表示重复次数,除此之外,还有一个作用就是用于捕获,. 捕获性分组
var color = "#808080";
var output = color.replace(/#(d+)/,"$1"+"~~");//自然也可以写成 "$1~~"
console.log(RegExp.$1);//808080
console.log(output);//808080~~
以上, var url = "www.google.google.com";
var re = /([a-z]+).1/;
console.log(url.replace(re,"$1"));//"www.google.com"
以上,相同部分的”google”字符串只被替换一次. 非捕获性分组
var color = "#808080";
var output = color.replace(/#(?:d+)/,"$1"+"~~");
console.log(RegExp.$1);//""
console.log(output);//$1~~
"#808080".match(/#(?:d+)/); //["#808080"]
正则表达式高阶技能-零宽断言(环视)零宽断言,又叫环视. 环视只进行子表达式的匹配,匹配到的内容不保存到最终的匹配结果,由于匹配是零宽度的,故最终匹配到的只是一个位置. 环视按照方向划分,有顺序和逆序两种(也叫前瞻和后瞻),按照是否匹配有肯定和否定两种,组合之,便有4种环视. 4种环视并不复杂,如下便是它们的描述. (?:pattern) 非捕获性分组,匹配pattern的位置,但不捕获匹配结果.也就是说不创建反向引用,就好像没有括号一样.
(?=pattern) 顺序肯定环视,匹配后面是pattern 的位置,不捕获匹配结果.
(?!pattern) 顺序否定环视,匹配后面不是 pattern 的位置,不捕获匹配结果.
(?<=pattern) 逆序肯定环视,匹配前面是 pattern 的位置,不捕获匹配结果.
(?<!pattern) 逆序否定环视,匹配前面不是 pattern 的位置,不捕获匹配结果.
非捕获性分组由于结构与环视相似,故列在表中,以做对比. 以上4种环视中,目前 javaScript 中只支持前两种,也就是只支持 顺序肯定环视 和 顺序否定环视. 顺序肯定环视:
'Windows(?=2000)'
匹配 "Windows2000" 中的 "Windows"; 不匹配 "Windows3.1" 中的 "Windows"
顺序否定环视:
'Windows(?!2000)'
匹配 "Windows3.1" 中的 "Windows"; 不匹配 "Windows2000" 中的 "Windows"
实例: var str = "123abc789",s;
//没有使用环视,abc直接被替换
s = str.replace(/abc/,456);
console.log(s); //123456789
//使用了顺序肯定环视,捕获到了a前面的位置,所以abc没有被替换,只是将3替换成了3456
s = str.replace(/3(?=abc)/,3456);
console.log(s); //123456abc789
//使用了顺序否定环视,由于3后面跟着abc,不满意条件,故捕获失败,所以原字符串没有被替换
s = str.replace(/3(?!abc)/,3456);
console.log(s); //123abc789
正则表达式之一 :exec 方法用正则表达式模式在字符串中查找,并返回该查找结果的第一个值(数组),如果匹配失败,返回null。 rgExp.exec(str)
返回数组
注意:在匹配后,rgExp 的 lastIndex 属性被设置为匹配文本的最后一个字符的下一个位置。lastIndex并不在返回对象的属性中,而是正则表达式对象的属性。 例子1:不含子表达式的正则表达式exec方法循环应用 !function RegExpTest(){
var src="http://sumsung753.blog.163.com/blog/I love you!";
// 注意g将全文匹配,不加将永远只返回第一个匹配。
var re = /w+/g;
var arr;
// exec使arr返回匹配的第一个,while循环一次将使re在g作用寻找下一个匹配。
while((arr = re.exec(src)) !=null){
document.write(arr.index + "-" + re.lastIndex + ":" + arr + "<br/>");
for(key in arr){
document.write(key + "=>" + arr[key] + "<br/>");
}
document.write("<br/>");
}
}()
结果: 0-4:http
0=>http
index=>0
input=>http://sumsung753.blog.163.com/blog/I love you!
7-17:sumsung753
0=>sumsung753
index=>7
input=>http://sumsung753.blog.163.com/blog/I love you!
18-22:blog
0=>blog
index=>18
input=>http://sumsung753.blog.163.com/blog/I love you!
23-26:163
0=>163
index=>23
input=>http://sumsung753.blog.163.com/blog/I love you!
27-30:com
0=>com
index=>27
input=>http://sumsung753.blog.163.com/blog/I love you!
31-35:blog
0=>blog
index=>31
input=>http://sumsung753.blog.163.com/blog/I love you!
36-37:I
0=>I
index=>36
input=>http://sumsung753.blog.163.com/blog/I love you!
38-42:love
0=>love
index=>38
input=>http://sumsung753.blog.163.com/blog/I love you!
43-46:you
0=>you
index=>43
input=>http://sumsung753.blog.163.com/blog/I love you!
如果正则表达式中包含子表达式,那么输出结果将包含子匹配项 例子2:包含子表达式的正则表达式exec方法应用 !function execDemo(){
var r,re; // 声明变量。
var s = "The rain in Spain falls mainly in the plain";
re = /[w]*(ai)n/ig;
r = re.exec(s);
document.write(r + "<br/>");
for(key in r){
document.write(key + "-" + r[key] + "<br/>");
}
}()
//输出结果如下:
rain,ai
0-rain
1-ai
index-4
input-The rain in Spain falls mainly in the plain
例子3:包含子表达式的正则表达式exec方法循环应用 场景回顾获取html片段假如现在,js 通过 ajax 获取到一段 html 代码如下: var responseText = "<div data='dev.xxx.txt'></div><img src='dev.xxx.png' />";
现我们需要替换img标签的src 属性中的 “dev”字符串 为 “test” 字符串.
如下: var reg = /dev(?=[^']*png)/; //为了防止匹配到第一个dev,通配符前面需要排除单引号或者是尖括号
var str = responseText.replace(reg,"test");
console.log(str);//<div data='dev.xxx'></div><img src='test.xxx.png' />
当然,以上不止顺序肯定环视一种解法,捕获性分组同样可以做到. 那么环视高级在哪里呢? 环视高级的地方就在于它通过一次捕获就可以定位到一个位置,对于复杂的文本替换场景,常有奇效,而分组则需要更多的操作. 千位分割符
var str = "1234567890";
(+str).toLocaleString();//"1,234,567,890"
如上,toLocaleString() 返回当前对象的”本地化”字符串形式.
toLocaleString 方法特殊,有本地化特性,对于天朝,默认的分隔符是英文逗号. 因此使用它恰好可以将数值转化为千位分隔符形式的字符串. 如果考虑到国际化,以上方法就有可能会失效了. 我们尝试使用环视来处理下. function thousand(str){
return str.replace(/(?!^)(?=([0-9]{3})+$)/g,',');
}
console.log(thousand(str));//"1,890"
console.log(thousand("123456"));//"123,456"
console.log(thousand("1234567879876543210"));//"1,879,876,543,210"
上述使用到的正则分为两块. "[0-9]{3}" 表示连续3位数字.
"([0-9]{3})+" 表示连续3位数字至少出现一次或更多次.
"([0-9]{3})+$" 表示连续3的正整数倍的数字,直到字符串末尾.
那么 (?=([0-9]{3})+$) 就表示匹配一个零宽度的位置,并且从这个位置到字符串末尾,中间拥有3的正整数倍的数字.
正则表达式使用全局匹配g,表示匹配到一个位置后,它会继续匹配,直至匹配不到.
将这个位置替换为逗号,实际上就是每3位数字添加一个逗号.
当然对于字符串"123456"这种刚好拥有3的正整数倍的数字的,当然不能在1前面添加逗号. 那么使用 (?!^) 就指定了这个替换的位置不能为起始位置.
千位分隔符实例,展示了环视的强大,一步到位. 正则实现模板引擎var tmp = "An ${a} a ${b} keeps the ${c} away";
var obj = {
a:"apple",b:"day",c:"doctor"
};
function tmpl(t,o){
return t.replace(/${(.)}/g,function(m,p){
console.log('m:'+m+' p:'+p);
return o[p];
});
}
tmpl(tmp,obj);
//结果:
m:${a} p:a
m:${b} p:b
m:${c} p:c
"An apple a day keeps the doctor away"
正则表达式在H5中的应用H5中新增了 pattern 属性,规定了用于验证输入字段的模式,pattern的模式匹配支持正则表达式的书写方式. 默认 pattern 属性是全部匹配,即无论正则表达式中有无 “^”,“$” 元字符,它都是匹配所有文本. 注: pattern 适用于以下 input 类型:text,search,url,telephone,email 以及 password. 如果需要取消表单验证,在form标签上增加 novalidate 属性即可. 回文字符串function huiwen(str){
str = str.replace(/[Ws_]/gi,'');
return str.toLowerCase().split('').reverse().join('') == str.toLowerCase();
}
console.log(huiwen(' a bdba'));
console.log(huiwen(' a bdbc'));
trim去除首尾空格function _trim(str){
return str.replace(/^s+|s+$/,'');
}
//测试
console.log(_trim(' a bdba'));
console.log(_trim('ia bdba'));
将所有单词首字母大写name = 'aaa bbb ccc';
uw=name.replace(/bw+b/g,function(word){
return word.substring(0,1).toUpperCase()+word.substring(1);}
);
颜色字符串转换
function rgb2hex(sRGB) {
return sRGB.replace(/^rgb((d+)s*,s*(d+)s*,s*(d+))$/,function($0,$1,$2,$3){
return '#'+toHex($1)+toHex($2)+toHex($3);
});
}
function toHex(str){
return ('0'+(+str).toString(16)).slice(-2);
}
将字符串转换为驼峰格式
function cssStyle2DomStyle(sName) {
//使用正则将 前一位有-的字符替换为大写【-([a-z])】
//replace第二个参数为函数时:
//函数的第一个参数是匹配模式的字符 【t】
//接下来的参数是与模式中的子表达式匹配的字符,可以有0个或多个这样的参数。【m】
//接下来的参数是一个整数,代表匹配在被替换字符中出现的位置【i】
//最后一个参数是被替换字符本身【这里没有用到】
return sName.replace(/-([a-z])/g,function(t,m,i){return i?m.toUpperCase():m;})
}
将Doe,John替换为John,Doevar name = "Doe,John";
var n = name.replace(/(w+)s*,s*(w+)/,"$2,$1");
//John,Doe
img标签匹配var str = `<img src="http://image.163.com"></img>`;
var reg=`<img src="[."]*"></img>`;
var reg1=`<img src="[^"]*></img>`;
var reg2=`<img src="[^"]*"></img>`; //正确
var reg3=`<img src="[."]*></img>`;
var arr = str.match(new RegExp(reg2));
console.log(arr);
console.log(arr.length);
参考链接:完整的正则表达式: (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |