正则表达式的情势婚配
正则表达式
(regular expression
)是一个形貌字符情势的对象。javascript的RegExp
对象示意正则表达式,String
和RegExp
都定义了要领,后者运用正则表达式举行壮大的情势婚配和文本检索与替代功用
。Javascript
的正则表达式是Perl5
的正则表达式语法的大型子集,所以关于有Perl编程履历的顺序员来讲。进修Javascript
的正则表达式是小菜一碟。
正则表达式的意义
Javascript中的正则表达式运用RegExp
示意,能够运用RegExp()组织函数
来建立RegExp对象,不过RegExp对象更多的是经由过程一种特别的直接量语法来建立。就像经由过程引号包裹字符的体式格局来建立字符串直接量一样。正则表达式直接了定义为包括在一对斜杠(/)
之间的字符,比方:
var patterns = /s$/;
运转这段代码建立一个新的RegExp对象,并将它赋值给变量patterns。这个特别的RegExp对象用来婚配一切以字符“s”末端的字符串。用组织函数RegExp也能够定义一个与之等价的正则表达式,代码以下:
var pattern = new RegExp('s$');
正则表达式的情势划定规矩是由一个字符序列组成的。包括一切字母和数字在内,大多半的字符都是根据直接量仅形貌婚配的字符的。如此说来,正则表达式/java/
能够婚配任何包括“java”子串的字符串。除此以外,正则表达式中另有其他具有特别语义的字符,这些字符并不根据字面寄义举行婚配。比方,正则表达式/s$/
包括两个字符,第一个字符“s”根据字面寄义婚配,第二个字符“$”是一个具有特别语义的字符,用以婚配字符串的完毕。因而这个表达式能够婚配任何故“s”完毕的字符串。
RegExp直接量和对象的建立
就像字符和数字一样,顺序中每一个取值雷同的原始范例直接量均示意雷同的值,这是不言而喻的。顺序运转时每次碰到对象直接量(初始化表达式)诸如{}
和[]
的时刻都邑建立新对象。比方,假如在循环体中写var a = [];
,则每次遍历都邑建立一个新的空数组。
正则表达式直接量则与此差别,ECMAScript 3
范例划定,一个正则表达式直接量会在实行到它时转换为一个RegExp对象,统一段代码所示意正则表达式直接量的每次运算都返回统一个对象
。ECMAScript 5
范例则做了相反的划定,统一段代码所示意的正则表达式直接量的每次运算都返回新对象
。IE一向都是根据ECMAScript 5的范例完成的,多半最新版本的浏览器也最先遵照ECMAScript 5,只管如今该规范并为周全普遍履行。以以下代码:
function getReg() {
var reg = /[a-z]/;
reg.foo = "bar";
return reg;
}
var reg = getReg();
var reg2 = getReg();
console.log(reg === reg2); // 在Firefox 3.6中返回true,在Firefox 4+中返回flase
reg.foo = "baz";
console.log(reg2.foo); // 在Firefox 3.6中返回“baz”,在Firefox 4+中返回“bar”
缘由能够在ECMAScript 5
范例第24页和第247页中找到,也就是说在ECMAScript 3
范例中,用正则表达式建立的RegExp对象会同享一个实例,而在ECMAScript 5
中则是两个自力的实例。很明显ECMAScript 5
的范例更相符开发者的希冀。
直接量字符串
正如上文提到的,正则表达式中的一切字母和数字都是根据字面寄义举行婚配的。JavaScript正则表达式也支撑非字母的字符婚配,这些字符经由过程反斜线()作为前缀举行转义。比方,转义字符n用来婚配换行符。
o
NUL字符(u0000)t
制表符(u0009)n
换行符(u000A)v
垂直制表符(u000B)f
换页符(u000C)r
回车符(u000D)xnn
有十六进制数nn指定为拉丁字符,比方,x0A等价于nuxxxx
由十六进制数xxxx指定的Unicode字符,比方u0009等价于tcX
控制字符^X,比方,cJ等价于换行符n
在正则表达式中,很多(共18个)标点标记具有特别寄义,它们是
^ $ . * + ? : ! = \ / | [ ] { } ( )
在接下来的几节里,我们将进修这些标记的寄义,某些相符只要在正则表达式的某些高低文中才具有特别寄义,在其他高低文中则被当做直接量处置惩罚。然则,假如想在正则表达式中运用这些字符的直接量举行婚配,则必需运用前缀“,这是一条通用的划定规矩。其他标点标记(比方@和引号)没有特别寄义,在正则表达式中根据字面寄义举行婚配。
假如不记得那些标点标记须要反斜线转移,能够运用每一个标点标记前都加上反斜线。别的须要注重,很多字符和数字在有反斜线做前缀是也有特别寄义`,所以关于想根据直接量举行婚配的字母和数字,举行不要用反斜线对其转义。固然,想要在正则表达式中根据直接量婚配反斜线自身,则必需运用反斜线将其转义。比方,正则表达式“/\/”用以婚配任何包括反斜线的字符串。
字符类
将直接量字符串
零丁放进方括号内就组成了字符类
(character class
)。一个字符类能够婚配它所包括的恣意字符。因而,正则表达式/[abc]/
就和字母“a”、“b”、“c”中的恣意一个都婚配。定义否认字符类
时,将一个“^”字符做为左方括号内的第一字符。正则表达式/[^abc]/
婚配的是“a”、“b”、“c”以外的一切字符。字符类能够运用连字符
来示意字符局限。要婚配拉丁字母表中的小写字母,能够运用/[a-z]/
,要婚配拉丁字母表中任何字母和数字,则运用/[a-zA-Z0-9]/
。
由于某些字符类异常经常使用,由于在JavaScript的正则表达式语法中,运用了这些特别字符的转义字符来示意它们。比方,s
婚配的是空格符、制表符和其他Unicode空白符(\o、 \t、 \n、 \v、 \f、 \r等),S
婚配的黑白Unicode 空白符的字符。下面列出了这些字符,而且总结了字符类的语法(注重,有些字符类转义字符只能婚配ASCII字符,还没有扩展到能够处置惩罚Unicode字符,但能够经由过程十六进制示意要领来显现定义Unicode字符类,比方,/[u2e80-u9fff]/
用来婚配一切汉字)。
[...]
方括号内的恣意字符[^...]
不在方括号内的恣意字符.
除换行符和其他Unicode行终止符以外的恣意字符w
任何ASCII字符组成的单词,等价于[a-zA-Z0-9]W
任何不适ASCII字符组成的单词,等价于[^a-zA-Z0-9]s
任何Unicode空白符S
任何非Unicode空白符的字符,注重W和S的差别d
任何ASCII数字,等价于[0-9]D
除了ASCII数字以外的任何字符,等价于[^0-9][b]
推格直接量(惯例)
注重,在方括号以内也能够写这些特别转义字符。比方,由于\s婚配一切的空白符,\d婚配的是一切数字,由于/[\d\s]/婚配的就是恣意空白符或许数字。注重,这里有一个惯例。下面我们将会看到转义符\b具有的特别寄义,当用在字符类时,它示意的是退格字符,所以要在正则表达式中根据直接量示意一个退格符,只须要运用具有一个元素的字符类/[\b]/。
反复
用方才学过的正则表达式的语法,能够把两位数形貌成/dd/
,四位数形貌成/dddd/
。然则如今为止,还没有一种要领能够用来形貌恣意多位的数字在世形貌由三个字母和一个数字组成的字符串。这些正则表达式语法中较为庞杂的情势都提到了正则表达式中某元素的”反复涌现次数”。
我们在正则情势以后追随用以制订字符反复的标记。由于某些反复品种异常经常使用,因而就有一些特地用于示意这类状况的特别字符。比方,“+”用以婚配前一个情势的一个或多个副本。下面总结了这些示意反复的正则语法。
{n,m}
婚配前一项最少n次,但不能超过m次{n,}
婚配前一项n次或许更屡次{n}
婚配前一项n次?
婚配前一项0次或许1次,也就是说前一项是可选的,等价于{0,1}+
婚配前一项1次或许屡次,等价于{1,}*
婚配前一项0次或许屡次,等价于{0,}
这里有一些例子:
var reg1 = /\d{2,4}/ // 婚配2~4个数字
var reg2 = /\w{3}\d?/ // 准确婚配三个单词和一个可选数字
var reg3 = /\s+java\s+/ // 婚配前后带有一个或多个空格的字符串“java”
var reg4 = /[^(]*/ // 婚配一个或多个非左括号的字符
在运用“*”和“?”时要注重,由于这些字符能够婚配0个字符,因而它们许可什么都不婚配。比方,正则表达式/a*/现实与字符串“bbbb”婚配,由于这个字符串含有0个a。
非贪欲的反复
上面列出的婚配反复字符是尽量多的婚配,而且许可后续的正则表达式继承婚配。因而,我们称之为“贪欲的
”婚配。我们一样能够运用正则表达式举行非贪欲婚配
。只须在待婚配的字符后追随一个问号即可:“??”、“+?”、“*?”或“{1,5}?”。比方,正则表达式/a+/
能够婚配一个或多个一连的字符a。当运用“aaa”作为婚配字符串时,正则表达式会婚配它的三个字符。然则/a+?/
也能够婚配一个或多个一连字母a,但它是尽量少地婚配。我们一样将“aaa”作为婚配字符串,但后一个情势只能婚配第一个a。
运用非贪欲
的婚配情势所获得的效果能够和希冀并不一致。斟酌以下正则表达式/a+b/
,它能够婚配一个或多个a,以及一个b。当运用“aaab”作为婚配字符串时,她会婚配全部字符串,如今再试一下非贪欲婚配的版本/a+?b/
,它婚配尽量少的a和一个b。当用它来婚配“aaab”时,你希冀它能婚配一个a和末了一个b。但现实上,这个情势却婚配了全部字符串,和该情势的贪欲婚配一摸一样。这是由于正则表达式的情势婚配总是会寻觅字符串中第一个能够婚配的位置。由于该婚配是从字符串的第一个字符最先的。因而在这里不斟酌他的子串中更短的婚配。
挑选、分组和援用
正则表达式的语法还包括制订挑选项
、子表达式分组
和援用前一个子表达式的特别字符
。字符“|”用于支解供挑选的字符。比方,/ab|cd|ef/
能够婚配“ab”,能够能够婚配符串“cd”,还能够婚配字符串“ef”。/d{3}|[a-z]{4}/
婚配的时三位数字或许四个小写字母。
注重,挑选项的尝试婚配序次是从左到右
,直到发明婚配项。假如左边的挑选项婚配,就会疏忽右边的婚配项,纵然它发作更好的婚配。因而,当正则表达式/a|ab/
婚配字符串“ab”时,它只能婚配第一个字符。
正则表达式中的圆括号有多种作用。第一个作用是把零丁的项组合成子表达式,以便能够像处置惩罚一个自力的单位那样用“|”、“ * ”、“ + ”或许“ ? ”等来对单位内的项举行处置惩罚。比方,/java(Script)?/
能够婚配字符串“java”,厥后能够有“Script”也能够没有。/(ab|cd)+|ef/
能够婚配字符串“ef”,也能够婚配字符串“ab”或许“cd”的一次或屡次反复。比方,将“font-size”改成“fontSize”:
var str = "font-size";
str = str.replace(/-(\w)/,function(str,$1){
return $1.toUpperCase();
});
console.log(str); // => fontSize
在正则表达式中,圆括号的另一个作用是在完全的情势中定义子情势。当一个正则表达式成功地和目的字符串互相婚配时,能够从目的字符串中抽出和圆括号汇总的字母是相婚配的部份(我们将在随后的部份中看到怎样获得这些婚配的子串)。比方,嘉定我们正在检索的情势是一个或多个小写字母背面追随了一名或多位数字,则能够运用情势/[a-z]+d+/
。但假定我们真正体贴的是每一个婚配尾部的数字,那末假如将情势的数字部份放在括号中(/[a-z]+(d+)/
),就能够从检索到的婚配中抽取数字了。以下:
var reg = /[a-z]+\d+/;
var str = 'abcde123';
str.match(reg);
// => ["abcde123"]
var reg2 = /[a-z]+(\d+)/;
str.match(reg2);
// => ["abcde123", "123"]
带圆括号的表达式的另一个用处就是许可在统一正则表达式的后部援用前面的子表达式。这是经由过程在字符“”
后加一名或多位数字来完成的。这个数字指定了带圆括号的子表达式在正则表达式中的位置。比方,1
援用的是第一个带圆括号的子表达式,3
援用的是第三个带圆括号的子表达式。注重,由于子表达式能够嵌套别的一个子表达式,所以它的题目是介入计数的左括号的位置。比方,下面的正则表达式中,嵌套的子表达式([Ss]cript)能够运用2
来指代
var reg = /([Jj]ava([Ss]cript)?)\sis\s(fun\w*)/;
var str = 'javascript is fun that java';
var match = str.match(reg);
console.log(match);
// => ["javascript is fun", "javascript", "script", "fun"]
对正则表达式中前一个子表达式的援用,并非只对子表达式的援用,而是指与谁人情势相婚配的文本的援用。如许,援用
能够用于实行一条束缚,即一个字符串各个零丁部份包括的是完全雷同的字符。比方,下面的正则表达式婚配的就是位于单引号或双引号以内的0个或多个字符。然则,它并不请求左边和右边的引号婚配(即到场的两个引号都是单引号或都是双引号):
var reg = /['"][^'"]*['"]/;
var str = '"hello\'';
reg.test(str); // => true
假如要婚配左边和右边的引号完全雷同,能够运用以下援用:
var reg = /(['"])[^'"]*\1/;
var str = '"hello\'';
reg.test(str); // => false
由于左边和右边的引号不一致,所以false。1
婚配的是第一个带圆括号的子表达式所婚配的情势。在这个例子中,存在如许一条束缚,那就是左边的引号必需和右边的引号相婚配。正则表达式不许可用双引号括起来的内容有单引号,反之亦然。不能在字符类中运用这类援用,所以下面的写法黑白法的:
var reg = /(['"])[^\1]*\1/;
var str = '"hello\'';
reg.test(str); // => false
正如上面重点标注的那段申明。对正则表达式中前一个子表达式的援用,并非只对子表达式的援用,而是指与谁人情势相婚配的文本的援用
所以这个是false。
在接下来,我们会看到一种带圆括号的子表达式的援用,这是正则表达式的检索和替代操纵的壮大特征
之一。
一样,在正则表达式中不必建立带数字编码的援用
,也能够对子表达式举行分组
。它不是以“ ( ”和“ ) ”举行分组,而是以“ (?: ”和“ ) ”来举行分组,比方,斟酌下面这个情势:
var reg = /([Jj]ava(?:[Ss]cript)?)\sis\s(fun\w*)/;
var str = 'javascript is fun that java';
var match = str.match(reg);
// => ["javascript is fun", "javascript", "fun"]
我们会发明这里婚配的效果跟前面婚配的效果“["javascript is fun", "javascript", "script", "fun"]
”比拟,少了一个"script"
。这是由于子表达式(?:[sS]cript)仅仅用于分组,不介入援用。因而复制标记”?”能够应用到各个分组。这类革新的圆括号并不天生援用,所以这个正则表达式中,2
援用了与(funW*)
婚配的文本。
下面是对正则表达式的挑选、分组和援用运算符做了总结。
| 挑选,婚配的是该标记左边的子表达式或右边的子表达式
(…) 组合,将几个项组合为一个单位,这个单位可经由过程“ * ”、“ ? ”、“ + ”和“ | ”等标记加以润饰,而且能够记着和这个组合相婚配的字符串以供今后的援用运用
(?:…) 只组合,把项组合到一个单位,但不影象和改组相婚配的字符
\n 和第n个分组第一次婚配的字符相婚配,组是圆括号中的子表达式(也多是嵌套的),组索引是从左到右的左括号,“(?:”情势的分组不介入编码
指定婚配位置
正如前面所引见的,正则表达式中的多个元素才能够婚配字符串中的一个字符。比方,s
婚配的只是一个空白符。另有一些正则表达式的元素婚配的是字符之间的位置,而不是现实的字符。比方,b
婚配一个单词的边境,即位于w(ASCII单词)字符和W(非ASCII单词)之间的边境,或位于一个ASCII单词与字符串的最先或完毕之间的边境。像b
如许的元素不婚配某个可见的字符,它们指定婚配发作的正当位置。偶然我们称这些元素为正则表达式的锚
,由于它们将情势定位在搜刮字符串的特定位置上。最经常使用的锚元素是^
,它是用来婚配字符串的肇端位置,锚元素$
用以婚配字符串的完毕位置。
比方,要婚配单词“javascript”,能够运用正则表达式/^[Jj]ava[Ss]cript$/
。假如想婚配”java”这个单词自身(不像在“JavaScript”中作为单词的前缀),能够运用正则表达式/sJava/
,能够婚配前后都有空格的单词“java”。然则如许做有两个题目,第一,假如“java”涌如今字符串的最先或许末端,就是婚配不成功,除非最先和末端处各有一个空格。第二个题目是,当找到了与之婚配的字符串时,它返回的婚配字符串的前端和后端都有空格没这并非我们想要的。因而我们运用单词的边境b来替代真正的空格符s举行婚配(或定位)。如许正则表达式就写成了/b[Jj]avab/
。元素B
将把婚配的锚点定位在不适单词的边境的地方。因而正则表达式/B[Ss]cript/
于“JavaScript”和“posrscript”婚配,然则不与“script”和“Scripting” 婚配。
var reg =/\bjava\b/;
var str = 'javascript is more fun that java';
str.match(reg); // => ["java"]
var str2 = 'javascript is more fun that javac';
str.match(reg); // => null
恣意正则表达式都能够作为锚点前提。就像上面例子中/bjavab/
中的”java”。假如在富豪“ (?= ”和“ ) ”之间到场一个表达式,他就是一个先行断言
,用以申明圆括号内的表达式必需准确婚配,但并非真正意义上的婚配。比方,要婚配一种经常使用的顺序设计语言的名字,但只在厥后有冒号时才婚配,能够运用/[Jj]ava([Ss]cript)?(?=:)/
。这个正则表达式能够婚配“Javascript: beautiful language”中的“JavaScript”,然则不能婚配“java in a Nutshell”中的“Java”,由于它背面没有冒号。
var reg =/[Jj]ava([Ss]cript)?(?=\:)/;
var str1 = "Javascript: beautiful language";
str1.match(reg); // => ["Javascript", "script"]
var str2 = "java in a Nutshell";
str2.match(reg); // => null
带有“ (?! ”的断言是负向先行断言,用一指定接下来的字符都不必婚配。比方,/Java(?!Script)[A-Z]w*/
能够婚配“Java”后追随一个大写字母和恣意多个ASCII单词,但Java后不能追随“Script”。它能够婚配”JavaBeans“,然则不能婚配”Javanese“。
var reg = /Java(?!Script)[A-Z]\w*/;
var str = "JavaBeans";
str.match(reg); // => ["JavaBeans"]
^ 婚配字符串的开首,再多行检索中,婚配一行的开首
$ 婚配字符串的末端,再多行检索中,婚配一行的末端
\b 婚配一个单词的边境,简言之,就是位于字符w和W之间的位置,或位于字符W和婚配字符串的开首或许末端的位置
\B 婚配非单词边境的位置
(?=pattern) 正向先行断言,要就接下来的字符都与pattern婚配,然则不能包括婚配pattern的那些字符
(?!pattern) 负向(反向)先行断言,要就接下来的字符都不与pattern婚配
润饰符
正则表达式中的语法另有末了一个知识点,即正则表达式的润饰符
,用以申明高等婚配情势的划定规矩。和之前议论的正则表达式语法差别,润饰符是放在“/”标记以外的,也就是说,它们不是涌现两条斜线之间,而是第二条斜线以后。JavaScript支撑三个润饰符,润饰符“i”
用以申明情势婚配是不辨别大小写。润饰符“g”
申明*情势婚配应当是全局的,*也就是说,应当找出被检索字符串中一切的婚配。润饰符“m”
用以在多行情势中实行婚配,在这类情势下,假如待检索的字符串包括多行,那末^
和$
锚字符除了婚配全部字符串的最先和末端以外,还能婚配每行的最先和完毕。比方正则表达式/java$/im
能够婚配“java”也能够婚配“Javan is fun”。
var reg = /java$/im;
var str1 = 'java';
str1.match(reg); // => ["java"]
var str2 = 'java\n is fun';
str2.match(reg); // => ["java"]
这些润饰符能够恣意组合,比方,要想不辨别大小写婚配字符串中的第一个单词“java”,能够运用不辨别大小写的润饰符来定义正则表达式/bjavab/i
。要想婚配字符串中一切单词,则须要增加润饰符g:/bjavab/gi
。
i 实行不辨别大小写的婚配
g 实行一个全局婚配,简言之,即找到一切的婚配,而不是在找到第一个以后住手
m 多行婚配情势,^婚配一行的开首和字符串的开首,$婚配行的末端和字符串的末端
猎取指定的querystring
function param(key, url) {
var reg = new RegExp("(?:^|\\?|#|&)" + key + "=([^&#]*)(?:$|&|#)", "i");
var o = reg.exec(url || location.href);
return o ? encodeURI(o[1]) : "";
}
猎取一切的querystring
function getAllParam() {
var reg=/[?&]([^=?&]+)=([^=?&]+)/ig
var url={};
while(reg.exec(location.href)){
url[RegExp.$1]=RegExp.$2;
}
return url;
}