1.0宽断言
(?=test) 匹配后面是test的但是不捕获
(?!test) 匹配后面不是test的不捕获
(摘自正则30分钟):用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们像\b,^,$那样用于指定一个位置。
例如千分符:‘122231223123‘.replace(/(?=(?!^)(\d{3})+$)/g,‘,‘);
2.贪婪与懒惰
*、+ 为贪婪 表示尽可能多的匹配
*?、+? 为懒惰 表示尽可能少的匹配
如:
"<div>a</div><div>b</div>".match(/<div>.*<\/div>/); 得到["<div>a</div><div>b</div>"]
.*表示除了回车以外0个或多个字符 尽可能多的匹配字符 直到遇到</div>结束 所以会匹配到最后的那个</div>
"<div>a</div><div>b</div>".match(/<div>.*?<\/div>/); 得到["<div>a</div>"]
.*? 表示除了回车以外0个或多个字符 尽可能少的匹配字符 直到遇到</div>结束 所以会匹配第一个出现的</div>
3. match 与exec,replace
当match 没有全局匹配时 效果和exec 是一样的 返回匹配的数组 ,第一个元素为第一次出现的匹配的表达式,第二个元素为第一次匹配的表达式的子表达式如果有的话,第三个元素依此类推。
如:"abc abc".match(/a(bc)/); 返回["abc", "bc"] ;“abc abc”中第二个abc并不会匹配
当match 有全局匹配时 返回匹配的数组 ,数组每个元素对应匹配的表达式 ,这个时候子表达式将不会捕获
如:"abc abc".match(/a(bc)/g) 返回 ["abc", "abc"] ;全局匹配对应的表达式 ,子表达式没有捕获
replace 和 match 的全局匹配有点区别 ,replace 不管全局或非全局匹配都会捕获子表达式
如: "abc abc".replace(/a(bc)/,"$1"); 得到 "bc abc"
"abc abc".replace(/a(bc)/g,"$1"); 得到 "bc bc"
"aaabac".replace(/(\w)\1+/g,‘-‘) 得到 "-bac"
另外正则对象在匹配后会保存上次匹配值的索引,因此再次使用同一个正则对象时最好先把正则对象的lastIndex值置为0
eg:var a = new RegExp("b","g");
console.log(a.test(‘abc‘)); //true
console.log(a.lastIndex); //2
console.log(a.test(‘abc‘)); //false
console.log(a.lastIndex) //0
4. 知识点总结
1.exec
语法:
reg.exec(str)
如
果 exec() 找到了匹配的文本,则返回一个结果数组。否则,返回 null。此数组的第 0 个元素是与正则表达式相匹配的文本,第 1 个元素是
与 RegExpObject 的第 1 个子表达式相匹配的文本(如果有的话),第 2 个元素是与 RegExpObject 的第 2 个子表达式
相匹配的文本(如果有的话),以此类推.
除了数组元素和 length 属性之外,exec() 方法还返回两个属性。index 属性声明的是匹配文本的第一个字符的位置。input 属性则存放的是被检索的字符串 string。
在调用非全局的 RegExp 对象的 exec() 方法时,返回的数组与调用方法 String.match() 返回的数组是相同的。
当 RegExpObject 是
一个全局正则表达式时。它会在 RegExpObject 的 lastIndex 属性指定的字符处开始检索字符串 string。
当 exec() 找到了与表达式相匹配的文本时,在匹配后,它将把 RegExpObject 的 lastIndex 属性设置为匹配文本的最后一个
字符的下一个位置。这就是说,您可以通过反复调用 exec() 方法来遍历字符串中的所有匹配文本。当 exec() 再也找不到匹配的文本时,它将返
回 null,并把 lastIndex 属性重置为 0。
eg:
/123/.exec(‘123 123‘); //返回["123"]
全局reg时 如果要匹配所有 要通过循环匹配实现:
var a; var r=[]; var str="123 123 ab1232"; var reg = new RegExp("123","g"); while((a=reg.exec(str))!=null){ console.log(a); console.log(reg.lastIndex); // r.push(a[0]); } console.log(r) //所有匹配的
2.match
语法:
stringObject.match(regexp)
如果 regexp 没有标志 g,那么 match() 方法就只能在 stringObject 中执行一次匹配。如果没有找到任何匹配的文本, match() 将返回 null。否则,它将返回一个数组。
如
果 regexp 具有标志 g,则 match() 方法将执行全局检索,找到 stringObject 中的所有匹配子字符串。若没有找到任何匹配
的子串,则返回 null。如果找到了一个或多个匹配子串,则返回一个数组。不过全局匹配返回的数组的内容与前者大不相同,它的数组元素中存放的
是 stringObject 中所有的匹配子串,而且也没有 index 属性或 input 属性。
3.零宽断言
所谓0宽断言 是指捕获的宽度为0 ,也就是只匹配不捕获,括号不会引起分组。
(?=X)正向断言,假定该位置后跟的是X
(?!X) 正向否定断言,假设该位置后跟的不是X
(?<=X)反向断言,假设该位置前跟的是X
(?<!X)反向否定断言,假设该位置前跟的不是X
可惜javascript不支持反向断言 (?<=X) 和 (?<!X)
还有个(?:X) 在js中这个应该不能称为0宽断言,因为它会捕获。
(?:X)是该位置出现X,并且捕获X,但是这里的括号不会引起分组。
比如:
/123(a)/.exec(‘123 123a‘); //返回 ["123a","a"] //匹配123后面是a的字符串 ,常规的括号引起了分组
/123(?:a)/.exec(‘123 123a‘); //返回["123a"] 匹配123后面是a的字符串并且捕获了a 但是不会分组
/123(?!a)/.exec(‘123a 123‘); //返回 ["123"] 匹配该位置后面不是a的字符串,也就是在正则‘123’的后面不是a的字符串。 没有捕获a也没有引起分组
/123(?=a)/.exec(‘123a 123‘); //返回 ["123"] 匹配该位置后面是a的字符串,也就是在正则‘123’的后面是a的字符串。 没有捕获a也没有引起分组
匹配html的应用:
/<html>(?=([\s\S]*?<head>))\1(?=([\s\S]*?<title>))\2(?=([\s\S]*?<\/title>))\3(?=([\s\S]*?<\/head>))\4(?=([\s\S]*?<body>))\5(?=([\s\S]*?<\/body>))\6[\s\S]*?<\/html>/
五. 附加知识点:
使用RegExp的显式构造函数,语法为:new RegExp("pattern"[,"flags"])。
使用RegExp的隐式构造函数,采用纯文本格式:/pattern/[flags]。
pattern部分为要使用的正则表达式模式文本,是必须的。
在第一种方式中,pattern部分以JavaScript字符串的形式存在,需要使用双引号或单引号括起来,这时首尾不需要‘/‘。
在第二种方式中,pattern部分嵌套在两个“/”之间,不能使用引号。
由于JavaScript字符串中的“\”是一个转义字符,因此,使用显式构造函数创建RegExp实例对象时,应将原始正则表达式中的“\”用“\\”替换
如:var reg1 = new RegExp("\\d{2}");
var reg2 = /\d{2}/;
var reg = new RegExp("^(\\+|-)?\\d+(\.\\d{0,2})?$"); //可有两位小数的浮点数
含变量的时候:
var a = "abc",
reg3 = new RegExp("^\\d" + a + "\\d$");
由于正则表达式模式文本中的转义字符也是“\”,如果正则表达式中要匹配原义字符“\”,在正则表达式模式文本中要以“\\”来表示,当使用显式构造函数的方式创建RegExp实例对象的时候,就需要使用“\\\\”来表示原义字符“\”。
var reg = new RegExp(\\\\)。
下面再复习下最常用的 test exec match search replace indexOf split 7个方法
var str = "" ,str1 = ""; //字符串
var reg = new RegExp(); //reg对象
var x = [] ; //返回的数组
g //全局匹配
i //不区分大小写
m //多行模式匹配
1.test
格式: reg.test(str); // 返回true 或false;
eg: /(a)\w+/.test("abcde") //返回true;
2.exec
格式:reg.exec(str); //返回一个数组 数组第一项为匹配的表达式 如果有匹配的子表达式则数组第二项为子表达式 以此类推。exec永远返回与第一个匹配相关的信息,不管有没有g
eg: /a(b)\w+/.exec("abcdef"); //返回的数组 x[0] = “abcdef” ,x[1] = "b";
/ab\w+/g.exec("abcde.fabc") //返回"abcde"
3.match
格式:str.match(reg); //返回一个数组 如果没有全局标识符g 则和exec一样,第一项 为匹配的表达式, 如果有匹配的子表达式则数组第二项为子表达式 以此类推。如果reg有全局标识符g 则 第一项 为第一个匹配的表达式,第二项 为第二个匹配的表达式 以此类推。
eg : "abcdef.abc".match(/a(b)\w+/); 返回 x[0] = “abcdef”,x[1] = "b";
"abcdef.abc".match(/a(b)\w+/g); 返回 x[0] = “abcdef” ,x[1] = "abc";
有关exec 和 match 的区别 这里有篇文章说的比较详细:http://makemyownlife.iteye.com/blog/395172
4.search
格式: str.search(reg); 返回从字符串中寻找指定值的位置,如果没找到则返回-1。它将忽略标志g。它同时忽略regexp 的lastIndex 属性,并且总是从字符串的开始进行检索。
eg: "abcdef".search(/a/) //返回0
5. indexOf
格式:str.indexOf(str1[,startIndex]) ; 返回从字符串中寻找指定值的位置,如果没找到则返回-1,可以指定开始检索的位置 ,和search的区别是str1不能是正则表达式。
6.replace
格式:str.replace(reg,str1) ; 返回 替换后的字符串 支持 i、g、m
eg: "abcdef".replace(/a/,"b") 返回:“bbcdef”;
"abcdefaa".replace(/a/ig,"b") 返回:“bbcdefbb”;
当str1为function时 返回的$1为正则表达式相匹配的文本,$2为子表达式匹配的文本,依此类推。
当str1为$1$2...时,则$1$2分别匹配相对应的子表达式。
eg:
var a = "abcealsk";
var c1 = a.replace(/(ab)c/ig,function($1,$2){return $1 + $2}); //返回:abcabealsk
var c2 = a.replace(/(ab)c/ig,"$1$2"); //返回:ab$2ealsk //此时$2没有对应的字表达式被当做字符串返回了。
比如常用的去掉字符串两端的空格
var a = " a a ";
var b = a.replace(/(^\s*)|(\s*$)/g,‘‘); 或 var b = a.replace(/^\s*(\w+.*\w+)*\s*$/,‘$1‘);
b为‘a a’
7.split
格式:str.split(reg); 返回按照reg划分后的数组 支持i
eg: "a_b_B_d_e".split(/b/i); 返回:[a_,_,_d_e]
练习:
测试是否含重复字符:
var a = "abcdefga";
var c = "abcdefg";
var b = /(\w)\w*\1/;
console.log(b.test(a)) //true
console.log(b.test(c)) //false
\m 表示第m次匹配的内容
eg:
/(span)\1/.test(‘spanspan‘) //true
/(span)(div)(td)\1\2\3/.test(‘spandivtdspandivtd‘); //true
eg 匹配xhtml标签 /^<(\w+)\s*.*>.*<\/\1>|<\w+\s*\/>$/.test("<span><img/></span>")