javascript正则
2016-11-11
本文所述正则表达式基本都是prel方式
【元字符】
( [ { \ ^ $ | ) ? * + .
【预定义特殊字符】
| 字符 | 正则 | 描述 |
| \t | /\t/ | 制表符 |
| \n | /\n/ | 换行符 |
| \r | /\r/ | 回车符 |
| \f | /\f/ | 换页符 |
| \a | /\a/ | alert字符 |
| \e | /\e/ | escape字符 |
| \cX | /\cX/ | 与X相对应的控制字符 |
| \b | /\b/ | 与回退字符 |
| \v | /\v/ | 垂直制表符 |
| \0 | /\0/ | 空字符 |
【字符类】
1:简单类
原则上正则的一个字符对应一个字符,位置必须严格匹配,如
/abc/.test('abc'); // true
可以用[]把它们括起来,让[]这个整体对应一个字符。如
/[abc]/.test("a"); //true
"cat,car,bar,box".match(/[cb]ar/g); //["car", "bar"]
2:负向类:
也是在括号里加限定符号,前面加个限定符号进行取反,表示匹配【必须】不能为括号里面的字符。
/[^abc]/.test("a"); //false
/[^abc]/.test(6); //true
/[\u4e00-\u9fa5]/.test('正则表达式'); //true
/[^\u4e00-\u9fa5]/.test(''正则表达式'); //false (注:\u4e00-\u9fa5 是指所有汉字的unicode编码范围)
3:范围类
使用"-"横线 控制范围 如下所示为 匹配为6-8的数字 后面{0,2} 为出现次数 0~2次 可以不出现 出现的话最多2次
"688883".match(/[6-8]{0,2}/); //["68"]
匹配6-8的数字 最少出现2次 最多出现4次
/[6-8]{2,4}/.test(777); //true
4:组合类
允许用中括号匹配不同类型的单个字符。
/[a-zA-Z]/.test('B');//true
/[8-9]/.test("8"); //true
/[a-c1-2]/.test("1"); //true
5:预定义类
| 字符 | 等同于 | 描述 |
| . | [^\n\r] | 除了换行和回车之外的任意字符 |
| \d | [0-9] | 数字字符 |
| \D | [^0-9] | 非数字字符 |
| \s | [\t\n\x0B\f\r] | 空白字符 |
| \S | [^\t\n\x0B\f\r] | 非空白字符 |
| \w | [a-zA-Z0-9] | 任何ASCII字符组成的单词 |
| \W | [^a-zA-Z0-9] | 任何不是ASCII字符组成的单词 |
/\d/.test("3"); // true
/\d/.test("aa");// false
/\s/.test(" "); // true
/\S/.test("神鹰"); // true
/./.test("神"); // true
/./.test(" "); // true
【量词】
顾名思义修饰词,修饰数量用词,例如匹配前端开发,最少也要/..../,如果长到10个字符甚至100个肯定是会“瘫痪”,所以需要数量量词来修饰数量
简单量词:
| 代码 | 类型 | 描述 |
|---|---|---|
| ? | 软性量词 | 出现零次或一次 |
| * | 软性量词 | 出现零次或多次(任意次) |
| + | 软性量词 | 出现一次或多次(至道一次) |
| {n} | 硬性量词 | 对应零次或者n次 |
| {n,m} | 软性量词 | 至少出现n次但不超过m次 |
| {n,} | 软性量词 | 至少出现n次(+的升级版) |
/[javascript]?/.test("nodjs"); //true
/[javascript]?/.test("nodjsjavascript"); //true
/[java]*/.test(" "); // true
/[javanodejs]+/.exec("java"); //["java"]
/[abc]{1}/.test("a"); // true 必须能匹配abc 中的某一个字符
/[abc]{1,2}/.exec("abc"); //["ab"]
以上列出的匹配重复字符是尽可能多地匹配,而且允许后续的正则表达式继续匹配。因为,我们称之为“贪婪的”匹配。随后我们即将介绍如何使其变为非贪婪的匹配。(能少吃就少吃点吧,吃那么多长肉啊~~~)
•用贪婪量词进行匹配时,它首先会将整会字符串当成一个匹配,如果匹配的话就退出,如果不匹配,就截去最后一个字符进行匹配,如果还不匹配,继续将最后一个字符截去进行匹配,直到有匹配为止。直到现在我们遇到的量词都是贪婪量词
•用惰性量词进行匹配时,它首先将第一个字符当成一个匹配,如果成功则退出,如果失败,则测试前两个字符,依些增加,直到遇到合适的匹配为止。(仅在贪婪量词后面加个"?"就可以成为惰性量词,"??","+?","*?","{1,5}?" 如"a+"是贪婪匹配的,"a+?"则是惰性的)
*支配性量词,在简单量词后加"+"加号。上面两种都有个不断尝试的过程,而支配性量词却只尝试一次,不合口味就算了。由于javascript不支持,所以本文不在叙述
贪婪量词栗子:
/a+/.exec("aaaaaabbbb"); //["aaaaaa"] 贪婪匹配
/a+?/.exec("aaaaabbbb"); //["a"] 惰性匹配
简单易懂吧,是不是so easy。好我们在来看一个让你瞬间懵逼的 贪婪 和 惰性匹配
/a+/.exec("aaa"); //["aaa"] 贪婪匹配
/a+?b/.exec("aaabbb"); //["aaab"] 惰性匹配
不是说好的惰性匹配不贪吃么 怎么吃了三个"a",尼玛~~~~这是因为正则表达式的模式匹配总是会寻找字符串第一个可能匹配的位置。由于该匹配是从字符串的第一个字符开始的,就是说把"aaabbb"先吃掉第一个a,第二个,然后第三个,发现还需要匹配一个b,找下看有没有b,发现第四个就是b,所以匹配完成,立即返回。就造成这种海市蜃楼的景象。还是懵圈?好,我们继续往下看~~(此处应该有思考)
/a+?bf?|b+?/.exec("abfaaaaaabfbb"); //["abf"] 惰性匹配
/a+?bf?|b+?/.exec("cacabfaaaaaabfbb"); //["abf"] 惰性匹配
明白否?(总得让人家找到一个abf的匹配吧,如果a 吃多了,那不能赖人家咯,因为我还需要继续找b和f呢,找到了的时候,就返回啦)
【分组】
到目前为止,我们只能一个字符到匹配,虽然量词的出现,能帮助我们处理一排密紧密相连的同类型字符。但这是不够的,下面该轮到小括号出场了,中括号表示范围内限制,大括号表示重复次数限制。小括号允许我们重复多个字符。
小括号作用one:把单独项组合成子表达式(写个括号可以把一串的东东组合成一个整体进行匹配,同时可以使用"|"、"*"、"+"、"?"进行修饰该表达式。so easy......让我们来探个栗子)听说点此会走桃花运,不妨试试...猛戳
alert(/java(script)?/.test('java')); //true
alert(/(ab)+|cd/.test('ab')); //true
alert(/(ab)+|cd/.test('ababab')); //true
小括号作用two:(在完整的模式中定义子模式,当一个正则表达式成功地和目标字符串成功匹配,可以从目标中抽出和圆括号的子模式相匹配的部分......一脸懵逼,让我们来探个栗子)听说点此会走桃花运,不妨试试...猛戳
var str = 'abc3'; alert(/(abc(\d{1,5}))+/.test(str)); //true alert('第一个括号匹配的内容===》'+RegExp.$1) //abc3 alert('第二个括号匹配的内容===》'+RegExp.$2) //3
应用场景栗子:听说点此会走桃花运,不妨试试...猛戳
在电商或者金融等平台开发中,一般需要用户输入身份证号、手机号,但是当用户查看时候不能全部显示出来吧,中间部分咱需要给他整成*号来展示,如支付宝.....显示身份证等敏感信息时,是酱紫的
1 var str = '131022199608085088'; 2 alert(str.replace(/(\d{3})(\d)*(\d{4})/g,'$1*************$3')); //"131*************5088" 3 alert('第一个括号匹配的内容===》'+RegExp.$1) //131 4 alert('第三个括号匹配的内容===》'+RegExp.$3) //5088 5 6 var str = '18311185623'; 7 alert(str.replace(/(^1(3|4|5|7|8)\d+)\d{4}(\d{4})$/,'$1*****$3')); //183*****5623 8 alert('第一个括号匹配的内容===》'+RegExp.$1) //183 9 alert('第三个括号匹配的内容===》'+RegExp.$3) //5623
小括号作用three:(带括号的表达式允许在同一正则表达式的后部引用前面的子表达式。通过在字符"\"后多加一位或多位数字实现的,数字含义就是指定带圆括号的子表达式在正则中的位置....十脸懵逼....)
让我们探个栗子:
比如我想使正则能够匹配 前面某部分和后面某部分必须一致才可以,通常写法如
/['"][^'"]*['"]/.test('"sdfsdfa"') //true
/['"][^'"]*['"]/.test('"sdfsdfa') //此处少了个双引号 false
两边必须由 两个单引号组成字符串 ,中间是 多个非单双引号或者0个 (注意会发现 后者 ['"] 跟前者一样 可以使用\n (此处n指子模式角标)进行引用 如下栗子:
/(['"][^'"]*\1)/.test('"asdfads"') //true
/(['"][^'"]*\1)/.test("asdfads") //false 前后必须由'"....."' 组成
如果想要使正则匹配和某处子模式一样的内容,也适用该模式
/(abv)\d{5}\1/.test('abv22222abv') //true
/(abv)\d{5}\1/.test('abv22222ab') //false 细心的你会发现最后少了个v,所以不能和abv正确完全匹配,别忘记哦~~~此处\1代表引用(abv)子模式的引用文本
【引用】
(?:)只组合,把项组合到一个单元,但不记忆与该组相匹配的字符 (因为对单项使用了括号,使之成为表达式,当使用?:..... 我们来看个栗子)听说点此会走桃花运,不妨试试...猛戳
1 //======不使用?: 分组引用时候是酱紫的====== 2 alert(/(a)(cc)\1/.test('acca')) //true 3 //a模式会产生分组引用,所以当前\1是指a子模式的引用 4 alert(/(a)(cc)\1/.test('acc')) //false 5 6 //======使用?: 分组引用时候是酱紫的====== 7 alert(/(?:a)|(cc)\1/.test('cc')) // flase 8 \1代表引用第一个子模式,因为第一个子模式使用了"?:",所以它并不会创建引用,也就是引用的后面cc子模式 9 10 alert(/(?:a)|(cc)\1/.test('cccc')) //true
【锚字符】
| 字符 | 含义 |
| ^ | 匹配字符串的开头,在多行检索中,匹配一行的开头 |
| $ | 匹配字符串的结尾,在多行检索中,匹配一行的结尾 |
| \b | 匹配一个单词的边界,简言之,就是位于字符\w和\W之间的位置,或位于字符\w和字符串的开头或者结尾之间的位置(但需要注意,[\b]匹配的是退格符) |
| \B | 匹配非单词边界的位置 |
| (?=p) |
零宽正向先行断言,要求接下来的字符都与p匹配,但不能包括匹配p的那些字符 (注:在正则中一个位置代表匹配一个字符,因为此处是零宽,即没有位置,所以匹配结果中不会包含该匹配内容) |
| (?!p) |
零宽负向先行断言,要求接下来的字符不与p匹配 (注:在正则中一个位置代表匹配一个字符,因为此处是零宽,即没有位置,所以匹配结果中不会包含该匹配内容) |
首先我们来看下^和$栗子:(^指定限定词 ,必须由该词开头 $指定限定词 ,必须由该词结尾。才可以正确匹配)
/^abc$/.test('abc') //true
/^abc$/.test('abcd') //false
/^abc$/.test('bbc') //false
//有个需求,要求用户必须为数字,而且最大为8为整数,2为小数
/^(([1-9]\d{0,7})|0)(\.\d{0,2})?$/.test(12312132.33);
接下来我们来看下零宽正向先行断言(?=p) 和 负宽正向先行断言(?=!P) 栗子:听说点此会走桃花运,不妨试试...猛戳("进入请按F12,在Console查看结果")
//如果aaa后紧跟着bbb 那就返回子表达式前面的aaa console.log(/aaa(?=bbb)/.exec("aaabbb")); //字符串中a和任意A-Z字符之间不能有b字符,有则匹配失败,反之成功,但是零宽断言匹配的文本不会返回 也就是aC console.log(/a(?!b)[A-Z]*/.exec('aC')); //['aC'] console.log(/a(?!b)[A-Z]*/.exec('abC')); //null
【修饰符】
| 字符 | 含义 |
| i | 执行不区分大小写的匹配 |
| g | 执行全局匹配,找到所有匹配,并不是找到第一个之后就停止 |
| m | 多行匹配,^匹配一行的开头和字符串的开头,$匹配行的结束和字符串的结束 |
关于修饰符i、g、m使用,请~~~~~你懂得~~~"戳我"~~~("进入请按F12,在Console查看结果")
//注:正则中默认是区分大小写的,所以当使用i修饰符后,即可关闭大小写区分 /abcD/i.test('abcd') //true /abcD/.test('abcd') //false //注:正则中不使用g修饰符默认匹配一个成功,就立即返回。不要问我正则exec方法为什么加了g也一直返回一个~~~~~稍后便知 'adad'.match(/ad/) //["ad"] 'adad'.match(/ad/g) //["ad", "ad"] 'adadad'.match(/ad/g) //["ad", "ad", "ad"] '<img src="aaa/111.jpg"/><img src="aaa/112.jpg"/>'.match(/<img [^>]*\/>/ig) //["<img src="aaa/111.jpg"/>", "<img src="aaa/112.jpg"/>"] '<img src="aaa/111.jpg"/><img src="aaa/112.jpg"/>'.match(/<img [^>]*\/>/i) //["<img src="aaa/111.jpg"/>"] //注:正则中不使用修饰符m默认匹配第一行,使用后多行匹配(\n是换行哦~~) /java$/i.test('java\nfun') //false /java$/im.test('java\nfun') //true
行啦!本文到此告一段落,不知道你看完此文是否全部理解,其实正则用法很强大,平时不用全部深入学习,用时翻翻笔记即可快速回忆就够啦;
还有一些小的东西要分享给大家,自己测试玩的~~~
console.log("http://mu.dianpu.hualala.com/#shop/857663/index".match(/[http|https]*:\/\/[\w*\.\/]*/gm));
console.log('{a bcd}abcd{a cd}efgh{a b1=c2 ccd}ijkl{a b3=c4 cd}mnop{a b5="b6" ecd}qrst{a b7="b8" cd}uvwxyz{a bb7="b8" 9cd}'.match(/\{a\s[a-z][a-z0-9]((=[a-z]\d\s[a-z]{2})||(=\"[a-z]\d\"\s[a-z]{2}))?\}/g));
console.log(/\d+@[\w]+\.([com]|[cn])+/.test('1274768069@qq.co'));
//要求:密码有 数字和特殊字符 或者 数字和大小写字母 或者 子母和特殊字符 6-20位字符
console.log(/((?=.*\d)(?=.*\D)|(?=.*[a-zA-Z])(?=.*[^a-zA-Z]))^.{6,20}$/.test('333666aa'));
当然,别人的文章结尾都会分享一些相关技术或参考~~本人也分享两个关于正则不错的学习网站,第一个是在线实时匹配正则,方便测试(请戳)。第二个是正则生成SVG导图,当正则较长、难理解的时候可以借助该网站进行生成svg导图,方便视觉上的查看
和思维理解(请戳) 上述两个网站国内可能需要FQ~~~(FQ)强烈推荐,免费且很快~~链接不一定长久有效
如果你有任何评论,问题或者补充,我很欢迎在文章评论中讨论。
祝大家学习Prel javascript正则顺利。前端之巅群号:512976409

浙公网安备 33010602011771号