摘要:也叫零宽度正回顾后发断言,它断言自身出现的位置的前面能匹配表达式。同时使用了两种断言匹配以空白符间隔的数字再次强调,不包括这些空白符。
缘起
正则表达式就是一把利器,拿出来的时候往往无往不利, 但是我们常常却将之束之高阁, 只因她不是那么漂亮,不那么让人印象深刻.
基础知识常用元字符
标识 | 说明 |
---|---|
. | 匹配除换行符以外的任意字符 |
w | 匹配字母或数字或下划线或汉字, 若仅限英文等价于[a-z0-9A-Z_] |
s | 匹配任意的空白符,包括空格,制表符(Tab),换行符,中文全角空格等 |
d | 匹配数字 |
匹配单词的开始或结束 | |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
反义字符
标识 | 说明 |
---|---|
W | 匹配任意不是字母,数字,下划线,汉字的字符 |
S | 匹配任意不是空白符的字符 |
D | 匹配任意非数字的字符 |
B | 匹配不是单词开头或结束的位置 |
[^x] | 匹配除了x以外的任意字符 |
[^aeiou] | 匹配除了aeiou这几个字母以外的任意字符 |
重复
标识 | 说明 |
---|---|
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
分支条件 |
为了解决类似下面的问题
(?0d{2}[) -]?d{8} 匹配类似(010)88886666,或022-22334455,或02912345678等电话号码. 首先是一个转义字符(,它能出现0次或1次(?),然后是一个0,后面跟着2个数字(d{2}),然后是)或-或空格中的一个,它出现1次或不出现(?),最后是8个数字(d{8})
分支条件就是将能够涉及到的所有情况都通过|列举出来, 相当于程序代码的||, 如果前部分满足条件, 则不会在判断后部分.
0d{2}-d{8}|0d{3}-d{7}这个表达式能匹配两种以连字号分隔的电话号码:一种是三位区号,8位本地号(如010-12345678),一种是4位区号,7位本地号(0376-2233445)。
(0d{2})[- ]?d{8}|0d{2}[- ]?d{8} 匹配3位区号的电话号码,其中区号可以用小括号括起来,也可以不用,区号与本地号间可以用连字号或空格间隔,也可以没有间隔
分组
使用()将满足条件的表达式隔离出来作为独立的一部分
如:
(d{1,3}.){3}d{1,3}
((2[0-4]d|25[0-5]|[01]?dd?).){3}(2[0-4]d|25[0-5]|[01]?dd?)
将2[0-4]d|25[0-5]|[01]?dd?当作一个整体即可
一些示例
aw*匹配以字母a开头的单词——先是某个单词开始处(b),然后是字母a,然后是任意数量的字母或数字(w*),最后是单词结束处()。
d+匹配1个或更多连续的数字。这里的+是和类似的元字符,不同的是匹配重复任意次(可能是0次),而+则匹配重复1次或更多次。
w{6} 匹配刚好6个字符的单词
零宽断言
查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们像,^,$那样用于指定一个位置,这个位置应该满足一定的条件(即断言).
标识 | 说明 |
---|---|
(?=exp) | 匹配exp前面的位置 |
(?<=exp) | 匹配exp后面的位置 |
(?!exp) | 匹配后面跟的不是exp的位置 |
(? | 匹配前面不是exp的位置 |
(?=exp)也叫零宽度正预测先行断言,它断言自身出现的位置的后面能匹配表达式exp。比如w+(?=ing),匹配以ing结尾的单词的前面部分(除了ing以外的部分),如查找I"m singing while you"re dancing.时,它会匹配sing和danc。
(?<=exp)也叫零宽度正回顾后发断言,它断言自身出现的位置的前面能匹配表达式exp。比如(?<=re)w+会匹配以re开头的单词的后半部分(除了re以外的部分),例如在查找reading a book时,它匹配ading。
(?<=s)d+(?=s),同时使用了两种断言, 匹配以空白符间隔的数字(再次强调,不包括这些空白符)。
为了解决:
w*q[^u]w*匹配包含后面不是字母u的字母q的单词。但是如果多做测试(或者你思维足够敏锐,直接就观察出来了),你会发现,如果q出现在单词的结尾的话,像Iraq,Benq,这个表达式就会出错。这是因为[^u]总要匹配一个字符,所以如果q是单词的最后一个字符的话,后面的[^u]将会匹配q后面的单词分隔符(可能是空格,或者是句号或其它的什么),后面的w*b将会匹配下一个单词,于是w*q[^u]w*就能匹配整个Iraq fighting。负向零宽断言能解决这样的问题,因为它只匹配一个位置,并不消费任何字符。现在,我们可以这样来解决这个问题:w*q(?!u)w*。
(?!exp)也叫零宽度负预测先行断言, 断言此位置的后面不能匹配表达式exp, d{3}(?!d)匹配三位数字,而且这三位数字的后面不能是数字;((?!abc)w)+匹配不包含连续字符串abc的单词。
(?也叫零宽度负回顾后发断言, 断言此位置的前面不能匹配表达式exp:(?
一个更复杂的例子:(?<=<(w+)>).*(?=1>)匹配不包含属性的简单HTML标签内里的内容。(?<=<(w+)>)指定了这样的前缀:被尖括号括起来的单词(比如可能是),然后是.*(任意的字符串),最后是一个后缀(?=1>)。注意后缀里的/,它用到了前面提过的字符转义;1则是一个反向引用,引用的正是捕获的第一组,前面的(w+)匹配的内容,这样如果前缀实际上是的话,后缀就是了。整个表达式匹配的是和之间的内容(再次提醒,不包括前缀和后缀本身)。
贪婪与懒惰
贪婪: 尽可能匹配最长的字符串
懒惰: 匹配满足条件的第一个字符串
懒惰限定符
标识 | 说明 |
---|---|
*? | 重复任意次,但尽可能少重复 |
+? | 重复1次或更多次,但尽可能少重复 |
?? | 重复0次或1次,但尽可能少重复 |
{n,m}? | 重复n到m次,但尽可能少重复 |
{n,}? | 重复n次以上,但尽可能少重复 |
a.*?b匹配最短的,以a开始,以b结束的字符串。如果把它应用于aabab的话,它会匹配aab(第一到第三个字符)和ab(第四到第五个字符)
为什么第一个匹配是aab(第一到第三个字符)而不是ab(第二到第三个字符)?简单地说,因为正则表达式有另一条规则,比懒惰/贪婪规则的优先级更高:最先开始的匹配拥有最高的优先权——The match that begins earliest wins。关键字
match
语法: str.match(reg), 参数可传入字符串或者正则表达式.
关键注意正则表达式是否携带g, 判断实现全局匹配.
如果匹配成功, 返回匹配的值, 取返回数据的[0]元素; 如果失败,返回null
var str = "aaabbbcccffffdeeefff"; strResult = str.match(/aaa(S*)fff/); console.log(strResult); /* 返回一个类数组, 可使用Array.prototype.slice.call(strResult)转化为真正的数组 ["aaabbbcccffffdeeefff", "bbbcccffffdeee", index: 0, input: "aaabbbcccffffdeeefff", groups: undefined] ["原字符串", "截取出来的字符串", "位置编码", "输入", "组"] */
exec
语法:reg.exec(str)
检索字符串中指定的值。匹配成功返回一个数组,匹配失败返回null。
test
直接用来判断是否正确, 比较简单
compile
compile() 方法用于改变 RegExp。
compile() 既可以改变检索模式,也可以添加或删除第二个参数。
var reg=/hello/; console.log(reg.exec("hellojs"));//["hello"] reg.compile("Hello"); console.log(reg.exec("hellojs"));//null reg.compile("Hello","i"); console.log(reg.exec("hellojs"));//["hello"]match和exec对比
相似点:
match和exec在匹配成功时返回的都是数组,在没有匹配上时返回的都是null
不同点
1.全局匹配
当不使用全局匹配的时候,match和exec基本一致
var s = "aaa bbb ccc"; var reg = /w+/;//没有g var rs_match = s.match(reg); var rs_exec = reg.exec(s); console.log("match:",rs_match); console.log("exec:",rs_exec);
当使用全局匹配的时候,match和exec返回数据不同
match直接以数组的形式返回匹配的所有数据
exec返回的数据的格式和未使用全局匹配一致, 但是是逐个匹配目标字符串. 返回的index下标能够获取第几个匹配的初始位置.
var s = "aaa bbb ccc"; var reg = /w+/g;//有g var rs_match1 = s.match(reg); var rs_match2 = s.match(reg); var rs_exec1 = reg.exec(s); var rs_exec2 = reg.exec(s); console.log("match1:",rs_match1); console.log("match2:",rs_match1); console.log("exec1:",rs_exec1); console.log("exec2:",rs_exec2);
2.分组
无全局匹配分组时,match和exec返回结果相同。
由于正则表达式采用了括号分组,所以在返回匹配结果的同时,依次返回该结果的所有分组, 如上面示例str.match(/aaa(S*)fff/)返回结果, 类数组的第二个元素就是分组(()中的数据)的元素.
var s = "aaa1 bbb2 ccc3"; var reg = /(w+)(d{1})/;//两个分组,无g var rs_match1 = s.match(reg); var rs_match2 = s.match(reg); var rs_exec1 = reg.exec(s); var rs_exec2 = reg.exec(s); console.log("match1:",rs_match1); console.log("match2:",rs_match1); console.log("exec1:",rs_exec1); console.log("exec2:",rs_exec2);
全局匹配分组时,match和exec返回结果不同。
match会返回所有匹配到的结果;
exec会返回本次匹配到的结果,若表达式中出现分组,则会依次返回本次匹配的全部分组:
var s = "aaa1 bbb2 ccc3"; var reg = /(w+)(d{1})/g; var rs_match1 = s.match(reg); var rs_match2 = s.match(reg); var rs_exec1 = reg.exec(s); var rs_exec2 = reg.exec(s); var rs_exec3 = reg.exec(s); var rs_exec4 = reg.exec(s); console.log("match1:",rs_match1); console.log("match2:",rs_match1); console.log("exec1:",rs_exec1); console.log("exec2:",rs_exec2); console.log("exec3:",rs_exec3); console.log("exec4:",rs_exec4);replace使用
正则表达式构造函数:new RegExp("pattern"[,"flags"]);
正则表达式替换变量函数:stringObj.replace(RegExp, replace Text);
//下面的例子用来获取url的两个参数,并返回urlRewrite之前的真实Url var reg=new RegExp("(http://www.qidian.com/BookReader/)(d+),(d+).aspx","gmi"); var url="http://www.qidian.com/BookReader/1017141,20361055.aspx"; //方式一,最简单常用的方式 var rep=url.replace(reg,"$1ShowBook.aspx?bookId=$2&chapterId=$3"); console.log(rep); // http://www.qidian.com/BookReader/ShowBook.aspx?bookId=1017141&chapterId=20361055 //方式二 ,采用固定参数的回调函数 var rep2=url.replace(reg,function(m,p1,p2,p3){ console.log("mmmm => ", m, p1,p2,p3) return p1+"ShowBook.aspx?bookId="+p3+"&chapterId="+p3 }); alert(rep2); //方式三,采用非固定参数的回调函数 var rep3=url.replace(reg,function(){var args=arguments; return args[1]+"ShowBook.aspx?bookId="+args[2]+"&chapterId="+args[3];}); alert(rep3); //方法四 //方式四和方法三很类似, 除了返回替换后的字符串外,还可以多带带获取参数 var bookId; var chapterId; function capText() { var args=arguments; bookId=args[2]; chapterId=args[3]; return args[1]+"ShowBook.aspx?bookId="+args[2]+"&chapterId="+args[3]; } var rep4=url.replace(reg,capText); alert(rep4); alert(bookId); alert(chapterId); //使用test方法获取分组 var reg3=new RegExp("(http://www.qidian.com/BookReader/)(d+),(d+).aspx","gmi"); reg3.test("http://www.qidian.com/BookReader/1017141,20361055.aspx"); //获取三个分组 console.log(RegExp.$0) console.log(RegExp.$1); // http://www.qidian.com/BookReader/ console.log(RegExp.$2); // 1017141 console.log(RegExp.$3); // 20361055参考文档
探究js正则匹配方法:match和exec
正则表达式30分钟入门教程
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/98529.html
摘要:遵循特定规则,利用操作符,终止节点和其他非终止节点,构造新的字符串非终结符是表示字符串的树的内部节点。语法中的生产具有这种形式非终结符终结,非终结符和运算符的表达式语法的非终结点之一被指定为根。 大纲 基于状态的构建 基于自动机的编程 设计模式:Memento提供了将对象恢复到之前状态的功能(撤消)。 设计模式:状态允许对象在其内部状态改变时改变其行为。 表驱动结构* 基于语法的构...
摘要:想阅读更多优质文章请猛戳博客一年百来篇优质文章等着你正则表达式或用于匹配字符串的各个部分下面是我创建正则表达式的备忘单。 想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你! 正则表达式或regex用于匹配字符串的各个部分 下面是我创建正则表达式的备忘单。 匹配正则 使用 .test() 方法 let testString = My test string; let t...
摘要:所以我们整理了一个应用安全备忘录,以帮助你在部署启动应用程序的时候进行安全检查。这可以保护应用程序不被攻击。应该用日志记录下来,而不是显示给用户。 本人的博客http://www.wjs.photo/,感兴趣的可以看看哦,基于NodeJs框架ThinkJs 本文翻译自 www.risingstack.com ,并非逐字逐句的翻译,有错误的地方请指出,谢谢啦 应用程序的安全就像是你房间里...
阅读 1597·2023-04-25 14:12
阅读 1069·2021-08-27 16:24
阅读 2532·2019-08-30 15:44
阅读 2911·2019-08-30 13:16
阅读 1664·2019-08-29 14:10
阅读 964·2019-08-29 13:54
阅读 1295·2019-08-29 13:09
阅读 1801·2019-08-26 18:37