js正则表达式
在线正则测试:http://regexpal.com/
一点的学习,关于正则的会都放在这里:
基础知识:
特殊的元字符/保留字符:正则表达式中不参与匹配的字符,如[],()
量词:如+,*,?,{3},{3,}里的3,{3,6}
字符组简写式/转义字符:如\d
捕获分组:用( )括起来,后面可以用\1对捕获的内容进行后向引用,如(\d)\d\1匹配三个数字,且第一位和第二位数字相同
非捕获分组:(?:pattern),匹配pattern但是不保存捕获内容,(?:t|T)(\d)\1匹配t11而不是t1t
量词贪心:默认会尽量多的匹配。量词首次尝试匹配整个字符串,若失败则回退一个字符再尝试(这个过程叫回溯),每次回退一个字符直到找到匹配内容或没有字符可以回退了。如a{1,3}会匹配baaab中的aaa;
量词懒惰/勉强:量词后加?,从目标的起始位置开始寻找匹配,每次检查一个字符,若失败则前进一位直到尝试匹配整个字符串。a{1,3}?会匹配baaab中的a和a和a;
/.../g: global
/.../i: ignoreCase
/.../m: multiline,没有m时,整个目标文本被当作一个字符串,^只匹配最开始的一个地方,/.../m时,^匹配每一行的开始。
/.../gsm: s:表示.除了匹配其他字符外,还匹配换行符\n
[1-3]
[369]
[,;]
\d,\D
[^0-9]
\w,\w
\s,\S
\b
\B
.
{3}
?
|:注意a|bc和(a|b)c的区别
^
$
1、关于\b
\b:匹配一个单词边界,除了空格外,“-”、“/”、“.”、“;”、“,”、“《”等标点符号都被当做单词边界(下划线‘_'不能界定边界),
如'ab_c-d;8<e f.g/h'.replace(/\b(\w)\b/g, '0$1')的结果是:ab_c-0d;08<0e 0f.0g/0h (注意最后一个h也被替换了,因为最开头和最后面默认有一个边界);
又如把2009-8-5转换成2009-08-05,可以‘2009-8-5'.replace(/\b(\d)\b/g, '0$1')=='2009-08-05'
2、关于\B
\B:匹配非单词边界。
如
"123456789".replace(/\d{3}\B/g,function(s){return s+',';});------"123,456,789"
"123456789".replace(/\B\d{3}/g,function(s){return s+',';});------"1234,567,89";
3、关于^和$
这两个分别匹配字符串的开始位置和结束位置。如/4$/表示要以4结尾;/^4$/则只匹配4,像434不匹配。
4、关于匹配汉字
/[\u4e00-\u9fa5]/表示匹配汉字,如把字符串a中所有汉字换成’-‘:a.replace(/[\u4e00-\u9fa5]/g,'-');检验字符串a中是否全是汉字:不是/^[\u4e00-\u9fa5]$/.test(a);这只会匹配一个汉字,应该是/^[\u4e00-\u9fa5]+$/.test(a);
5、关于$1...$9
RegExp对象的$1...$9属性是只读的,如果表达式模式中有括起来的子匹配,$1…$9属性值分别是第1个到第9个子匹配所捕获到的内容。如果有超过9个以上的子匹配,$1…$9属性分别对应最后的9个子匹配。如/^(\d{3,4})-(\d+)$/.test('079-8778');alert(RegExp.$1);alert(RegExp.$2);分别为079和8779.
如实现一个如下功能的函数:把1转换成‘1’,把1转换成‘12’,把1转换成‘12’,把1转换成‘123’,把1转换成‘123’,把1234转换成‘1,234’,把12345转换成‘12,345’,......把12345678转换成‘12,345,678’,
function groupByCommas(n) { var n=n.toString(); if((n.length<7)&&(n.length>3)) return n.replace(/(\d{3}$)/g,",$1"); else{ switch(n.length%3){ case 1: return n.replace(/(^\d{1})(\d{3}\B)/g,"$1,$2,"); case 2: return n.replace(/(^\d{2})(\d{3}\B)/g,"$1,$2,"); default: return n.replace(/(^\d{3})(\d{3}\B)/g,"$1,$2,") } } }
上面这种做法不对的,会把1234567890转换成‘1,234,567890’,下面的正确。
function groupByCommas(n) { var n=n.toString(); if(n.length<3) return n; else{ switch(n.length%3){ case 1: return n.replace(/(^\d{1})/g,"$1,").replace(/(\d{3}\B)/g,"$1,"); case 2: return n.replace(/(^\d{2})/g,"$1,").replace(/(\d{3}\B)/g,"$1,"); default: return n.replace(/(\d{3}\B)/g,"$1,") } } }
更好更简洁的方法如下:
function groupByCommas(n) { return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); }
\Bxxx表示xxx不是在边界开始的地方;
+表示重复至少一次;
():在被修饰匹配次数的时候,括号中的表达式表示作为整体被修饰;在取匹配结果的时候,括号中的表达式匹配到的内容可以被单独得到;
\d表示0-9中的任意一个;
{3}表示重复3次;
(?=xxx)表示前面字符的右边必须匹配xxx,可以理解为这只是这个缝隙的后面要匹配的内容,不影响xxx继续匹配正则表达式后面的内容。
如/window(?=NT|XP)/g只匹配'windowNTwindow7'中的window,而不是匹配windowNT,
(?!xxx)表示前面字符的右边必须不匹配xxx,同样不影响xxx继续匹配正则表达式后面的内容。
综上,/\B(?=(\d{3})+(?!\d))/g表示一个缝隙,不是单纯开始的缝隙,此缝隙右边必须有3个数字(这3个数字可以出现一次或多次),接着不能出现数字,也就是缝隙右边只能出现3的倍数个数字。
或者
str.replace(/(\d)(?=(\d{3})+(\.\d+)?$)/g,'$1,')
/(\d)(?=(\d{3})+(\.\d+)?$)/g表示匹配一个数字,这个数字后面要么的多组\d{3}结尾要么是多组\d{3}后跟着一个小数点和多位数字结尾。
或者
str..replace(/\B(\d{3})(?=(\d{3})*(\.\d+)?$)/g,',$1')
/\B(\d{3})(?=(\d{3})*(\.\d+)?$)/gb表示匹配一个三位数字,且不是最开头的三位数字,这三位数字后面要么啥也没有,要么后面是0组或多组\d{3},然后以一个小数点和多位数字结尾或是直接结尾。
补充内容:贪婪模式和非贪婪模式
如对于字符串“dxxxdxxxd”
/d(\w+)d/匹配完整的“dxxxdxxxd”,/d(\w+?)d/匹配完整的“dxxxd”。
贪婪模式:匹配次数尽可能多,
非贪婪模式:当在修饰匹配次数的特殊符号后再加上一个 "?" 号,则可以使匹配次数不定的表达式尽可能少的匹配,使可匹配可不匹配的表达式。
常用正则表达式:\b
只允许字母和空格: /^[a-zA-Z ]*$/
e-mail: /([\w\-]+\@[\w\-]+\.[\w\-]+)/
url: /\b(?:(?:https?|ftp):\/\/|www\.)[-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%=~_|]/i
计算匹配项出现的次数:
//注意是全局模式//g var p=/.cc/g,fullText='aaccbbccddcc'; p.exec(fullText); //["acc"] p.lastIndex; //4 p.exec(fullText); //["bcc"] p.lastIndex; //8 p.exec(fullText); //["dcc"] p.lastIndex; //12 p.exec(fullText); //null p.lastIndex; //0 p.exec(fullText); //["acc"] ......
所以计算次数为:
var count=0; while(p.exec(fullText)){count++;} return count;
如果希望对字符串'bbaaacc'匹配'aa'的次数为3,则:
var count=0,searchText='aa',fullText='baaa'; var p=new RegExp(searchText,'g');//在正则表达式中引入变量的方法 while(p.exec(fullText)){p.lastIndex-=searchText.length-1;count++;} return count;
.replace(/.../,...)
$& | Inserts the matched substring. |
$` | Inserts the portion of the string that precedes the matched substring. |
$' | Inserts the portion of the string that follows the matched substring. |
例如:
'dabc'.replace(/a/,'11$&')--------"d11abc"
'dabc'.replace(/a/,'11$`')--------"d11dbc"
'dabc'.replace(/a/,"11$'")--------"d11bcbc"
也可以.replace(reg, function), function参数为(match, $1, $2,...)
如: 'a-bc-de'.replace(/[-_](\w)/g,(match,$1)=>{console.log(match);return $1.toUpperCase()}) // 'aBcDe'