正则表达式的语法不再多说
正则RegExp类型有几个常用方法:
exec()
该方法是专门为捕获组而设计的。
例:
var text='I love cat and dog and panda';
var pattern=/I love cat( and dog( and panda)?)?/gi;
var matches=pattern.exec(text);
console.log(matches.input)//I love cat and dog and panda
console.log(matches.index)//0
console.log(matches)//[ 'I love cat and dog and panda',
' and dog and panda',
' and panda',
index: 0,
input: 'I love cat and dog and panda' ]
从例子中应该可以隐约体会到捕获组的意思。
我在学习正则表达式的时候,遇到的难点之一就是捕获组和非捕获组。
捕获组就是满足子表达式(就是被括号包含的表达式)的内容。它们是有编号的,方便以后引用。(无论是在正则表达式内外都可以引用)
注意,编号为0的捕获组,指的是符合正则表达式整体的内容。
引用方法是 "/" 加上一个数字。"/1" 引用第1对括号内匹配到的字符串。
那编号是怎么编呢?不然怎么知道引用哪个呢?编号根据左括号的顺序而定。
举个🌰
var text2='meowmeowmeowmeow'
var ptn=/(meow)\1/
var m=ptn.exec(text2);
console.log(m)//[ 'meowmeow', 'meow', index: 0, input: 'meowmeowmeowmeow' ]
看到了吧,\1表示第一个子表达式匹配的内容,所以输出的结果是两个meow。
还有另外一个🌰
var text='I love cat and dog and panda';
var pattern=/I love cat( and dog( and panda)?)?/gi;
var result=text.replace(pattern,'I love kitties and puppies$2')
console.log(result)//I love kitties and puppies and panda
但是有时候数字很不直观,大家知道正则表达式解读起来有时候麻烦,如果复杂过头,写的人自己都不知道写的什么鬼,那怎么办?可不可以自己命名啊?可以(任性
捕获组分为普通捕获组和命名捕获组。
普通捕获组就是刚才介绍的,只用数字编号;而命名捕获组,除了数字编号以外,可以自定义一个捕获组的名字。不过js貌似还不支持命名捕获组(溜了溜了
还有一个鬼登西叫做非捕获组,顾名思义就是我看到你了,但是我不会抓住你,找到你以后就放生你,所以非捕获组是不能引用的。
以下是常用的一些非捕获组
?:pattern 匹配pattern但不获取结果
?=pattern正向预查 比方说p1(?=p2),满足该表达式的内容为后面紧跟着p2的p1
?!pattern反向预查 后面不跟着p2的p1
而类似?<=的后瞻表达式,js也不支持,嘻嘻(再次溜
🌰🌰🌰🌰🌰🌰时间
尝试一下正向预查🌰:
var text2='Windows 95 and Windows 98 and Windows xp'
var ptn=/Windows(?= [\d]+\b)/g;
console.log(text2.replace(ptn,'meow'));//meow 95 and meow 98 and Windows xp
在看看反向预查🌰:
var text2='Windows 95 and Windows 98 and Windows xp'
var ptn=/Windows(?! [\d]+\b)/g;
console.log(text2.replace(ptn,'meow'));//Windows 95 and Windows 98 and meow xp
test()
如果文本有内容匹配正则表达式,返回true,否则返回false
构造函数的属性
摘抄了一下别人的博客,毕竟照着书手打很麻烦
input (简写为$_) 最近一次要匹配的字符串。
lastMatch(简写$&) 最近一次的匹配项
lastParen(简写$+) 最近一次匹配的捕获组。
leftContext(简写$`) input字符串中lastMatch之前的文本
rightContext(简写$') input字符串中lastMatch之后的文本
multiline(简写$*) 布尔值,表示是否所有表达式都使用多行模式。
在进行exec或者test操作以后,可从RegExp对象中提取上述信息
🌰🌰🌰🌰🌰🌰
var text='I love cat and dog and panda';
var pattern=/I love cat( and dog( and panda)?)?/gi;
var matches=pattern.test(text);
console.log(RegExp.input)//I love cat and dog and panda
console.log(RegExp.$_)//I love cat and dog and panda
console.log(RegExp["$_"])//I love cat and dog and panda
match()
返回符合正则表达式的内容(数组),未匹配返回null
🌰
var text2='Windows 95 and Windows 98 and Windows xp'
var ptn=/Windows(?: [\d]+\b)/g;
console.log(text2.match(ptn))//[ 'Windows 95', 'Windows 98' ]
search()
返回匹配到的位置索引,或者在失败时返回-1。
🌰
var text3='abcedefe';
var ptn3=/e/g;
var res=text3.search(ptn3);
console.log(res)//3
var res2=text3.search('/h/g');
console.log(res2)//-1
replace()
刚才讲解的捕获组中,🌰使用了replace方法。
text.replace(reg,替换的内容)
split()
var text3='abcedefe';
var ptn3=/e/;
var res=text3.split(ptn3);
console.log(res)//[ 'abc', 'd', 'f', '' ]
有一点特别魔幻,当时没有仔细看MDN,以为自己忽略了子表达式有什么其它的作用。
其实MDN写得一清二楚……
如果separator包含捕获括号(capturing parentheses),则其匹配结果将会包含在返回的数组中。
varmyString="Hello 1 word. Sentence number 2.";
varsplits=myString.split(/(\d)/);
console.log(splits)//[ 'Hello ', '1', ' word. Sentence number ', '2', '.' ]
当时自己写了一遍,想了想不对呀,split平时不是这个意思呀……
正则加不加括号不都一个意思吗……
下楼拿了个外卖,思考了10分钟,然后再看一遍MDN,呵呵。
嗯就死记硬背得了。反正这个函数任性么。
贪婪模式和懒惰模式
超级难点
添加修饰匹配次数的量词,默认为贪婪模式,尽可能多地匹配,如* + ?
而懒惰模式,是在修饰匹配次数的特殊符号后再加上一个 "?" 号,则可以使匹配次数不定的表达式尽可能少的匹配。
贪婪模式的原理:某个字符串str,使用贪婪模式的正则,首先它会从整个字符串开始观察是否符合正则,若不符合,从字符串结尾逐个减去字符,再次检测,以此类推,直到找到符合规则的字符串为止。
而懒惰模式则相反,它从字符串开头逐个添加再检索。
划考点:过滤html标签
思路:
标签是成对的,所以可以在后向引用获取;√
判断标签用〈、 〉符号判定,使用贪婪模式,可以解决其它嵌套标签;√
如果标签相同,比如
1.<div><div></div></div>,如果希望获取整个div,使用贪婪模式
2.<div></div><div></div>,如果希望获取前一个div,使用懒惰模式
要适当使用贪婪模式或者懒惰模式
最后用一道题检测下学习成果:
使用正则表达式实现数字添加千分位
例10000000000会变成10,000,000,000
大神在专栏里面已经讲的非常清楚。
文章首先阐明了位置的定义。
正则表达式里面,\b表示一个边界,表示\w与\W、^、$之间的位置。
之前一直认为边界符只是一个用来匹配位置的标记,并没有太大的作用,从来没有想过边界替换,所以好像也对这道题无从下手。
明确了位置的定义后,我们可以想象,千分位的添加,实质上就是每三个数字前面的位置添加一个逗号,而不必使用循环和各种判定条件。(我曾想过用split实现来着...)
那么要怎么表示\w之间的边界呢?需要对\b进行非操作吗?
在前面我介绍过正向预查,事实上正向预查可以表示特定的边界,因为可以看作它判定了预查对象前面的表达式+预查对象前面的位置。
现在刚学正则表达式,还不太熟练,我们一步步,一个个元字符和子表达式添加上去,练习自己对正则表达式的解读。
var s ="3102546864";
首先照着概念,我们希望取每3个数字的前面的边界
var re1=/(?=\d{3})/g;//结果: ,3,1,0,2,5,4,6,864
从开头判定,开头后面的确跟着3个数字310,于是开头的位置放置一个逗号;再右移,数字3的后面跟着3个数字102,于是3和102之间放置一个逗号……以此类推,直到864是最后一组3个数字。
var re2=/(?=(\d{3})+)/g;
把三个数字看作一个整体,设定为一个子模式,该子模式出现1次或以上时匹配成功。然而结果并没有改变,因为在replace中,+号是可有可无的。
接下来应该加什么限定条件,才可以令数字呈现3个一组,且不重复?是了,3个一组的数字是从字符串末尾开始计算的,那么加上一个结尾符如何?
var re3=/(?=(\d{3})+$)/g;//结果: 3,102,546,864
这个正则表达式的意思是寻找一个位置,该位置往后是1-n组,3个为一组的数字,且这些数字刚好截至到字符串的结尾(即找到数字的个数可以被3整除的一段了)
还有疑问吗?我们把具有迷惑性的g符去掉看看
var re4=/(?=(\d{3})+$)/;//结果: 3,102546864,可以知道确实是从目标位置开始界定了。刚才还在困惑正则表达式不是从前往后找吗,怎么倒可以从结尾数着3个一组?现在没有疑问了吧。
那么reg3的结果似乎已经OK了,是这样吗?如果数字的数量是3的倍数呢?
var s ="310254686";//结果却是 ,310,254,686
位置的概念涵盖了开始位和结束位,现在我们要把开始位排除掉。
两个方法,一个是(?!^),另一个是\B
var regexp1=/\B(?=(\d{3})+$)/g;
var regexp12=/(?!^)(?=(\d{3})+$)/g;
最后就是 s.replace(regexp1,','),耶