?
This document uses PHP Chinese website manual Release
概述
正則對(duì)象的屬性和方法
屬性
test方法
exec方法
字符串對(duì)象的方法
match方法
search方法
replace方法
split方法
匹配規(guī)則
字面量字符和元字符
字符類
重復(fù)類
量詞符
轉(zhuǎn)義符
修飾符
預(yù)定義模式
特殊字符
組匹配
參考鏈接
正則表達(dá)式(regular expression)是一種表達(dá)文本模式的方法,常常用作按照“給定模式”匹配文本的工具,比如給定一個(gè)Email地址的模式,然后用來確定一個(gè)字符串是否為Email地址。JavaScript的正則表達(dá)式體系是參照Perl 5建立的。
新建正則表達(dá)式有兩種方法。一種是使用字面量,以斜杠表示開始和結(jié)束。
var regex = /xyz/;
另一種是使用RegExp構(gòu)造函數(shù)。
var regex = new RegExp("xyz");
上面兩種寫法是等價(jià)的,都建立了一個(gè)內(nèi)容為xyz的正則表達(dá)式對(duì)象。
RegExp構(gòu)造函數(shù)還可以接受第二個(gè)參數(shù),表示修飾符(詳細(xì)解釋見下文)。
var regex = new RegExp("xyz", "i"); // 等價(jià)于 var regex = /xyz/i;
這兩種寫法在運(yùn)行時(shí)有一個(gè)細(xì)微的區(qū)別。采用字面量的寫法,正則對(duì)象在代碼載入時(shí)(即編譯時(shí))生成;采用構(gòu)造函數(shù)的方法,正則對(duì)象在代碼運(yùn)行時(shí)生成。考慮到書寫的便利和直觀,實(shí)際應(yīng)用中,基本上都采用字面量的寫法。
正則對(duì)象生成以后,有兩種使用方式:
使用正則對(duì)象本身的方法,將字符串作為參數(shù),比如regex.test(string)。
使用字符串對(duì)象的方法,將正則對(duì)象作為參數(shù),比如string.match(regex)。
下面逐一介紹這兩種使用方式。
正則對(duì)象的屬性主要如下:
ignoreCase:返回一個(gè)布爾值,表示是否設(shè)置了i修飾符,該屬性只讀。
global:返回一個(gè)布爾值,表示是否設(shè)置了g修飾符,該屬性只讀。
lastIndex:返回下一次開始搜索的位置。該屬性可讀寫,但是只在設(shè)置了g修飾符時(shí)有意義。
source:返回正則表達(dá)式的字符串形式(不包括反斜杠),該屬性只讀。
multiline:返回一個(gè)布爾值,表示是否設(shè)置了m修飾符,該屬性只讀。
下面是屬性應(yīng)用的實(shí)例。
var r = /abc/igm; r.ignoreCase // true r.global // true r.multiline // true r.lastIndex // 0 r.source // "abc"
test方法返回布爾值,用來驗(yàn)證字符串是否符合某個(gè)模式。
/cat/.test('cats and dogs') // true
上面代碼驗(yàn)證參數(shù)字符串之中是否包含cat,結(jié)果返回true。
如果正則表達(dá)式帶有g(shù)修飾符,則每一次test方法都從上一次結(jié)束的位置開始向后匹配。
var r = /x/g; var s = '_x_x'; r.lastIndex // 0 r.test(s) // true r.lastIndex // 2 r.test(s) // true r.lastIndex // 4 r.test(s) // false
上面代碼的正則對(duì)象使用了g修飾符,表示要記錄搜索位置。接著,三次使用test方法,每一次開始搜索的位置都是上一次匹配的后一個(gè)位置。
如果正則模式是一個(gè)空字符串,則匹配所有字符串。
new RegExp("").test("abc") // true
exec方法返回匹配結(jié)果。
var s = '_x_x'; var r1 = /x/; var r2 = /y/; r1.exec(s) // ["x"] r2.exec(s) // null
上面代碼表示,如果匹配成功,exec方法返回一個(gè)數(shù)組,里面是匹配結(jié)果。如果匹配失敗,返回null。
如果正則表示式包含圓括號(hào),則返回的數(shù)組會(huì)包括多個(gè)元素。其中,第一個(gè)元素是整個(gè)匹配成功的結(jié)果,后面的元素就是圓括號(hào)對(duì)應(yīng)的匹配成功的組,也就是說第二個(gè)元素就對(duì)應(yīng)第一個(gè)括號(hào),第三個(gè)元素對(duì)應(yīng)第二個(gè)括號(hào),以此類推。整個(gè)返回?cái)?shù)組的length屬性等于匹配成功的組數(shù)+1。
var s = '_x_x'; var r = /_(x)/; r.exec(s) // ["_x", "x"]
上面代碼的exex方法,返回一個(gè)數(shù)組。第一個(gè)元素是整個(gè)匹配的結(jié)果,第二個(gè)元素是圓括號(hào)匹配的結(jié)果。
exec方法的返回?cái)?shù)組還包含以下兩個(gè)屬性:
input:整個(gè)原字符串。
index:整個(gè)模式匹配成功的開始位置。
var r = /a(b+)a/; var arr = regex.exec("_abbba_aba_"); arr// ["abbba", "bbb"] arr.index// 1 arr.input// "_abbba_aba_"
上面代碼中的index屬性等于1,是因?yàn)閺脑址牡诙€(gè)位置開始匹配成功。
如果正則表達(dá)式加上g修飾符,則可以使用多次exec方法,下一次搜索的位置從上一次匹配成功結(jié)束的位置開始。
var r = /a(b+)a/g; var a1 = r.exec("_abbba_aba_"); a1 // ["abbba", "bbb"] a1.index // 1 r.lastIndex // 6 var a2 = r.exec("_abbba_aba_"); a2 // ["aba", "b"] a2.index // 7 r.lastIndex // 10 var a3 = r.exec("_abbba_aba_"); a3 // null a3.index // TypeError: Cannot read property 'index' of null r.lastIndex // 0 var a4 = r.exec("_abbba_aba_"); a4 // ["abbba", "bbb"] a4.index // 1 r.lastIndex // 6
上面代碼連續(xù)用了四次exec方法,前三次都是從上一次匹配結(jié)束的位置向后匹配。當(dāng)?shù)谌纹ヅ浣Y(jié)束以后,整個(gè)字符串已經(jīng)到達(dá)尾部,正則對(duì)象的lastIndex屬性重置為0,意味著第四次匹配將從頭開始。
利用g修飾符允許多次匹配的特點(diǎn),可以用一個(gè)循環(huán)完成全部匹配。
var r = /a(b+)a/g; var s = "_abbba_aba_"; while(true) { var match = r.exec(s); if (!match) break; console.log(match[1]); } // bbb // b
如果正則對(duì)象是一個(gè)空字符串,則exec方法會(huì)匹配成功,但返回的也是空字符串。
var r1 = new RegExp(""); var a1 = r1.exec("abc"); a1 // [""] a1.index // 0 r1.lastIndex // 0 var r2 = new RegExp("()"); var a2 = r2.exec("abc"); a2 // ["", ""] a2.index // 0 r2.lastIndex // 0
字符串對(duì)象的方法之中,有4種與正則對(duì)象有關(guān)。
match:返回匹配的子字符串。
search:按照給定的正則規(guī)則進(jìn)行搜索。
replace:按照給定的正則規(guī)則進(jìn)行替換。
split:按照給定規(guī)則進(jìn)行字符串分割。
下面逐一介紹。
match方法對(duì)字符串進(jìn)行正則匹配,返回匹配結(jié)果。
var s = '_x_x'; var r1 = /x/; var r2 = /y/; s.match(r1) // ["x"] s.match(r2) // null
從上面代碼可以看到,字符串的match方法與正則對(duì)象的exec方法非常類似:匹配成功返回一個(gè)數(shù)組,匹配失敗返回null。
如果正則表達(dá)式帶有g(shù)修飾符,則該方法與正則對(duì)象的exec方法行為不同,會(huì)返回所有匹配成功的結(jié)果。
var s = "abba"; var r = /a/g; s.match(r) // ["a", "a"] r.exec(s) // ["a"]
search方法返回第一個(gè)滿足條件的匹配結(jié)果在整個(gè)字符串中的位置。如果沒有任何匹配,則返回-1。該方法會(huì)忽略g參數(shù)。
'_x_x'.search(/x/)// 1
replace方法可以替換匹配的值,它接受兩個(gè)參數(shù),第一個(gè)是搜索模式,第二個(gè)是替換的內(nèi)容。
str.replace(search, replacement)
搜索模式如果不加g修飾符,就替換第一個(gè)匹配成功的值,否則替換所有匹配成功的值。
"aaa".replace("a", "b") // "baa" "aaa".replace(/a/, "b") // "baa" "aaa".replace(/a/g, "b") // "bbb"
上面代碼中,最后一個(gè)正則表達(dá)式使用了g修飾符,導(dǎo)致所有的b都被替換掉了。
replace方法的一個(gè)應(yīng)用,就是消除字符串首尾兩端的空格,下面給出兩種寫法。
var str = ' #id div.class '; str.replace(/^\s+|\s+$/g, '') // "#id div.class" str.replace(/^\s\s*/,'').replace(/\s\s*$/,'') // "#id div.class"
replace方法的第二個(gè)參數(shù)可以使用美元符號(hào)$,用來指代所替換的內(nèi)容。
$& 指代匹配的子字符串。
$` 指代匹配結(jié)果前面的文本。
$' 指代匹配結(jié)果后面的文本。
$n 指代匹配成功的第n組內(nèi)容,n是從1的自然數(shù)。
$$ 指代美元符號(hào)$。
"hello world".replace(/(\w+)\s(\w+)/,"$2 $1") // "world hello" "abc".replace("b", "[$`-$&-$']") // "a[a-b-c]c"
replace方法的第二個(gè)參數(shù)還可以是一個(gè)函數(shù),將匹配內(nèi)容替換為函數(shù)返回值。
"3 and 5".replace(/[0-9]+/g, function(match){ return 2 * match; }) // "6 and 10" var a = "The quick brown fox jumped over the lazy dog."; var pattern = /quick|brown|lazy/ig; a.replace( pattern, function replacer(match){ return match.toUpperCase(); } ); // The QUICK BROWN fox jumped over the LAZY dog.
作為replace方法第二個(gè)參數(shù)的替換函數(shù),可以接受多個(gè)參數(shù)。它的第一個(gè)參數(shù)是捕捉到的內(nèi)容,第二個(gè)參數(shù)是捕捉到的組匹配(有多少個(gè)組匹配,就有多少個(gè)對(duì)應(yīng)的參數(shù))。此外,最后還可以添加兩個(gè)參數(shù),倒數(shù)第二個(gè)參數(shù)是捕捉到的內(nèi)容在整個(gè)字符串中的位置(比如從第五個(gè)位置開始),最后一個(gè)參數(shù)是原字符串。下面是一個(gè)網(wǎng)頁(yè)模板替換的例子。
var prices = { "pr_1": "$1.99", "pr_2": "$9.99", "pr_3": "$5.00" }; var template = ".."; // some ecommerce page template template.replace( /(<span id=")(.*?)(">)(<\/span>)/g, function(match,$1,$2,$3,$4){ return $1 + $2 + $3 + prices[$2] + $4; } );
上面代碼的捕捉模式中,有四個(gè)括號(hào),所以會(huì)產(chǎn)生四個(gè)組匹配,在匹配函數(shù)中用$1到$4表示。匹配函數(shù)的作用是將價(jià)格插入模板中。
split方法按照正則規(guī)則分割字符串,返回一個(gè)由分割后的各個(gè)部分組成的數(shù)組。
str.split(separator, [limit])
該方法接受兩個(gè)參數(shù),第一個(gè)參數(shù)是分隔規(guī)則,第二個(gè)參數(shù)是返回?cái)?shù)組的最大成員數(shù)。
'a, b,c, d'.split(',') // [ 'a', ' b', 'c', ' d' ] 'a, b,c, d'.split(/, */) // [ 'a', 'b', 'c', 'd' ] 'a, b,c, d'.split(/, */, 2) [ 'a', 'b' ]
上面代碼使用正則表達(dá)式,去除了子字符串的逗號(hào)前面的空格。
"aaa*a*".split(/a*/) // [ '', '*', '*' ] "aaa**a*".split(/a*/) // ["", "*", "*", "*"]
上面代碼的分割規(guī)則是出現(xiàn)0次或多次的a,所以第一個(gè)分隔符是“aaa”,第二個(gè)分割符是“a”,將整個(gè)字符串分成三個(gè)部分。出現(xiàn)0次的a,意味著只要沒有a就可以分割,實(shí)際上就是按字符分割。
如果正則表達(dá)式帶有括號(hào),則括號(hào)匹配的部分也會(huì)作為數(shù)組成員返回。
"aaa*a*".split(/(a*)/) // [ '', 'aaa', '*', 'a', '*' ]
上面代碼的正則表達(dá)式使用了括號(hào),第一個(gè)組匹配是“aaa”,第二個(gè)組匹配是“a”,它們都作為數(shù)組成員返回。
下面是另一個(gè)組匹配的例子。
'a, b , '.split(/(,)/) // ["a", ",", " b ", ",", " "] 'a, b , '.split(/ *(,) */) // ["a", ",", "b", ",", ""]
正則表達(dá)式對(duì)字符串的匹配有很復(fù)雜的規(guī)則。下面一一介紹這些規(guī)則。
大部分字符在正則表達(dá)式中,就是字面的含義,比如/a/匹配a,/b/匹配b。它們都叫做“字面量字符”(literal characters)。
/dog/.test("old dog") // true
上面代碼中正則表達(dá)式的dog,就是字面量字符,所以/dog/匹配old dog,因?yàn)樗捅硎綿、o、g三個(gè)字母連在一起。
除了字面量字符以外,還有一部分字符有特殊含義,不代表字面的意思。它們叫做“元字符”(metacharacters),主要有以下幾個(gè)。
(1)點(diǎn)字符(.)
點(diǎn)字符(.)匹配除回車(\r)、換行(\n) 、行分隔符(\u2028)和段分隔符(\u2029)以外的所有字符。
/c.t/
上面代碼中的c.t匹配c和t之間包含任意一個(gè)字符的情況,只要這三個(gè)字符在同一行,比如cat、c2t、c-t等等,但是不匹配coot。
(2)位置字符
位置字符用來提示字符所處的位置,主要有兩個(gè)字符。
^ 表示字符串的起首。
$ 表示字符串的行尾。
/^test/.test("test123") // true /test$/.test("new test") // true /^test$/.test("test") // true /^test$/.test("test test") // false
(3)選擇符(|)
豎線符號(hào)(|)在正則表達(dá)式中表示“或關(guān)系”(OR),即 cat|dog 表示匹配cat或dog。
/11|22/.test("911") // true
字符類(class)表示有一系列字符可供選擇,只要匹配其中一個(gè)就可以了。所有可供選擇的字符都放在方括號(hào)內(nèi),比如[xyz] 表示x、y、z之中任選一個(gè)匹配。
/[abc]/.test("hello world") // false /[abc]/.test("apple") // true
上面代碼表示,字符串hello world不包含abc這三個(gè)字母中的任一個(gè),而字符串a(chǎn)pple包含字母a。
有兩個(gè)字符在字符類中有特殊含義。
(1)脫字符(^)
如果方括號(hào)內(nèi)的第一個(gè)字符是[^],則表示除了字符類之中的字符,其他字符都可以匹配。比如,[^xyz] 表示除了x、y、z之外都可以匹配。
/[^abc]/.test("hello world") // true /[^abc]/.test("bbc") // false
上面代碼表示,字符串hello world不包含字母abc中的任一個(gè),所以返回true;字符串bbc不包含abc以外的字母,所以返回false。
如果方括號(hào)內(nèi)沒有其他字符,即只有[^],就表示匹配一切字符,其中包括換行符,而點(diǎn)號(hào)(.)是不包括換行符的。
var s = 'Please yes\nmake my day!'; s.match(/yes.*day/) // null s.match(/yes[^]*day/) // [ 'yes\nmake my day']
上面代碼中,字符串s含有一個(gè)換行符,點(diǎn)號(hào)不包括換行符,所以第一個(gè)正則表達(dá)式匹配失敗;第二個(gè)正則表達(dá)式[^]包含一切字符,所以匹配成功。
注意,脫字符只有在字符類的第一個(gè)位置才有特殊含義,否則就是字面含義。
(2)連字符(-)
某些情況下,對(duì)于連續(xù)序列的字符,連字符(-)用來提供簡(jiǎn)寫形式,表示字符的連續(xù)范圍。比如,[abc]可以寫成[a-c],[0123456789]可以寫成[0-9],同理[A-Z]表示26個(gè)大寫字母。
/a-z/.test("b") // false /[a-z]/.test("b") // true
上面代碼中,當(dāng)連字號(hào)(dash)不出現(xiàn)在方括號(hào)之中,就不具備簡(jiǎn)寫的作用,只代表字面的含義,所以不匹配字符b。只有當(dāng)連字號(hào)用在方括號(hào)之中,才表示連續(xù)的字符序列。
以下都是合法的字符類簡(jiǎn)寫形式。
[0-9.,] [0-9a-fA-F] [a-zA-Z0-9-] [1-31]
上面代碼中最后一個(gè)字符類[1-31],不代表1到31,只代表1到3。
注意,字符類的連字符必須在頭尾兩個(gè)字符中間,才有特殊含義,否則就是字面含義。比如,
[-9]
就表示匹配連字符和9,而不是匹配0到9。
連字符還可以用來指定Unicode字符的范圍。
var str = "\u0130\u0131\u0132"; /[\u0128-\uFFFF]/.test(str) // true
另外,不要過分使用連字符,設(shè)定一個(gè)很大的范圍,結(jié)果選中意料之外的字符。最典型的例子就是[A-z],表面上它是選中從大寫的A到小寫的z之間52個(gè)字母,但是由于在ASCII編碼之中,大寫字母與小寫字母之間還有其他字符,結(jié)果就會(huì)出現(xiàn)意料之外的結(jié)果。
/[A-z]/.test('\\') // true
上面代碼中,由于反斜杠(\)的ASCII碼在大寫字母與小寫字母之間,結(jié)果會(huì)被選中。
{} 表示模式的重復(fù)次數(shù)。{n}表示重復(fù)n次,{n,}表示至少重復(fù)n次,{n,m}表示重復(fù)不少于n次,不多于m次。
/lo{2}k/.test("look") // true /lo{2,5}k/.test("looook") // true
? 表示某個(gè)模式出現(xiàn)1次或0次,等同于{0, 1}。
表示某個(gè)模式出現(xiàn)0次或多次,等同于 {0,}。
表示某個(gè)模式出現(xiàn)1次或多次,等同于 {1,}。
/t?est/.test("test") // true /t?est/.test("est") // true /t+est/.test("test") // true /t+est/.test("ttest") // true /t+est/.test("tttest") // true /t+est/.test("est") // false /t*est/.test("test") // true /t*est/.test("ttest") // true /t*est/.test("tttest") // true /t*est/.test("est") // true
以上三個(gè)量詞符,默認(rèn)情況下的匹配規(guī)則都是貪婪模式,即最大可能匹配,直到下一個(gè)字符不滿足匹配規(guī)則為止。比如,對(duì)于字符串“aaa”來說,/a+/將會(huì)匹配“aaa”,而不會(huì)匹配“aa”。為了將貪婪模式改為非貪婪模式,可以在量詞符后面加一個(gè)問號(hào),/a+?/將會(huì)只匹配“a”。
也就是說,星號(hào)(*)和加號(hào)(+)還有非貪婪模式的版本。
*?:表示某個(gè)模式出現(xiàn)0次或多次,匹配時(shí)采用非貪婪模式。
+?:表示某個(gè)模式出現(xiàn)1次或多次,匹配時(shí)采用非貪婪模式。
正則表達(dá)式中那些有特殊含義的字符,如果要匹配它們本身,就需要在它們前面要加上反斜杠。比如要匹配加號(hào),就要寫成+。
/1+1/.test("1+1") // false /1\+1/.test("1+1") // true
正則模式中,需要用斜杠轉(zhuǎn)義的,一共有12個(gè)字符:^、.、[、$、(、)、|、*、+、?、{和 \。需要特別注意的是,如果使用RegExp方法生成正則對(duì)象,轉(zhuǎn)義需要使用兩個(gè)斜杠,因?yàn)樽址畠?nèi)部會(huì)先轉(zhuǎn)義一次。
(new RegExp("1\+1")).test("1+1") // false (new RegExp("1\\+1")).test("1+1") // true
修飾符(modifier)表示模式的附加規(guī)則,放在正則模式的最尾部。
(1)g修飾符
默認(rèn)情況下,第一次匹配成功后,正則對(duì)象就停止向下匹配了。g修飾符表示全局匹配(global),加上它以后,正則對(duì)象將匹配全部符合條件的結(jié)果,主要用于搜索和替換。
var regex = /b/; var str = 'abba'; regex.test(str); // true regex.test(str); // true regex.test(str); // true
上面代碼連續(xù)做了三次匹配,都返回true。它的含義是如果不加g修飾符,每次匹配時(shí)都是從字符串頭部開始匹配。
var regex = /b/g; var str = 'abba'; regex.test(str); // true regex.test(str); // true regex.test(str); // false
上面代碼中,因?yàn)樽址癮bba”只有兩個(gè)“b”,所以前兩次匹配結(jié)果為true,第三次匹配結(jié)果為false。它的含義是加上g修飾符以后,每次匹配都是從上一次匹配成功處開始往后匹配。
(2)i修飾符
默認(rèn)情況下,正則對(duì)象區(qū)分字母的大小寫,加上i修飾符以后表示忽略大小寫(ignorecase)。
/abc/.test("ABC") // false/abc/i.test("ABC") // true
上面代碼表示,加了i修飾符以后,不考慮大小寫,所以模式abc匹配字符串ABC。
(3)m修飾符
有時(shí),字符串的頭部或尾部可能會(huì)有換行符。默認(rèn)情況下,正則對(duì)象會(huì)將換行符算入字符串的開頭或結(jié)尾。m修飾符表示多行模式(multiline),加上它以后,正則對(duì)象會(huì)忽略字符串頭部或尾部的換行符,即^和$會(huì)忽略換行符。
/world$/.test("hello world\n") // false /world$/m.test("hello world\n") // true
上面的代碼中,字符串結(jié)尾處有一個(gè)換行符。如果不加m修飾符,匹配不成功,因?yàn)樽址慕Y(jié)尾不是world;加上以后,換行符被省略,匹配成功。
修飾符可以多個(gè)一起使用。
var regex = /test/ig;
預(yù)定義模式指的是某些常見模式的簡(jiǎn)寫方式。
\d 匹配0-9之間的任一數(shù)字,相當(dāng)于[0-9]。
\D 匹配所有0-9以外的字符,相當(dāng)于[^0-9]。
\w 匹配任意的字母、數(shù)字和下劃線,相當(dāng)于[A-Za-z0-9_]。
\W 除所有字母、數(shù)字和下劃線以外的字符,相當(dāng)于/[^A-Za-z0-9_]/ 。
\s 匹配空格(包括制表符、空格符、斷行符等),相等于[\t\r\n\v\f]。
\S 匹配非空格的字符,相當(dāng)于[^\t\r\n\v\f]。
\b 匹配詞的邊界。
\B 匹配非詞邊界,即在詞的內(nèi)部。
下面是一些例子。
// \s的例子 /\s\w*/.exec("hello world") // [" world"] // \b的例子 /\bworld/.test("hello world") // true /\bworld/.test("hello-world") // true /\bworld/.test("helloworld") // false // \B的例子 /\Bworld/.test("hello-world") // false /\Bworld/.test("helloworld") // true
通常,正則表達(dá)式遇到換行符(\n)就會(huì)停止匹配。
var html = "<b>Hello</b>\n<i>world!</i>"; /.*/.exec(html)[0] // "<b>Hello</b>"
上面代碼中,字符串html包含一個(gè)換行符,結(jié)果點(diǎn)字符(.)不匹配換行符,導(dǎo)致匹配結(jié)果可能不符合原意。這時(shí)使用\s字符類,就能包括換行符。
var html = "<b>Hello</b>\n<i>world!</i>"; /[\S\s]*/.exec(html)[0] // "<b>Hello</b>\n<i>world!</i>" // 另一種寫法(用到了非捕獲組) /(?:.|\s)*/.exec(html)[0] // "<b>Hello</b>\n<i>world!</i>"
上面代碼中,[\S\s]
指代一切字符。
正則對(duì)象對(duì)一些不能打印的特殊字符,提供了表達(dá)形式。
\cX 表示 Ctrl-X
[\b] 匹配退格鍵(U+0008),不要與\b混淆。
\n 匹配換行鍵。
\r 匹配回車鍵。
\t 匹配制表符tab(U+0009)。
\v 匹配垂直制表符(U+000B)。
\f 匹配換頁(yè)符(U+000C)。
\0 匹配null字符(U+0000)。
\xhh 匹配一個(gè)以兩位十六進(jìn)制數(shù)表示的字符。
\uhhhh 匹配一個(gè)以四位十六進(jìn)制數(shù)表示的unicode字符。
(1)概述
正則表達(dá)式的括號(hào)表示分組匹配,括號(hào)中的模式可以用來捕獲分組的內(nèi)容。
var m = "abcabc".match(/(.)b(.)/); m // ["abc", "a", "c"]
上面代碼中,正則表達(dá)式/(.)b(.)/一共使用兩個(gè)括號(hào),第一個(gè)括號(hào)捕獲a,第二個(gè)括號(hào)捕獲c。
注意,使用組匹配時(shí),不宜同時(shí)使用g修飾符,否則match方法不會(huì)捕獲分組的內(nèi)容。
var m = "abcabc".match(/(.)b(.)/g); m // ["abc", "abc"]
上面代碼使用帶g修飾符的正則表達(dá)式,結(jié)果match方法只捕獲了匹配整個(gè)表達(dá)式的部分。
在正則表達(dá)式內(nèi)部,可以用\n引用括號(hào)匹配的內(nèi)容,n是從1開始的自然數(shù),表示對(duì)應(yīng)順序的括號(hào)。
/(.)b(.)\1b\2/.test("abcabc") // true
上面的代碼中,\1表示前一個(gè)括號(hào)匹配的內(nèi)容(即“a”),\2表示第二個(gè)括號(hào)匹配的內(nèi)容(即“b”)。
組匹配非常有用,下面是一個(gè)匹配網(wǎng)頁(yè)標(biāo)簽的例子。
var tagName = /<([^>]+)>[^<]*<\/\1>/; tagName.exec("<b>bold</b>")[1] // 'b'
上面代碼略加修改,就能捕獲帶有屬性的標(biāo)簽。
var html = '<b class="hello">Hello</b><i>world</i>'; var tag = /<(\w+)([^>]*)>(.*?)<\/\1>/g; var match = tag.exec(html); match[1] // "b" match[2] // "class="hello"" match[3] // "Hello" match = tag.exec(html); match[1] // "i" match[2] // "" match[3] // "world"
(2)非捕獲組
(?:x)稱為非捕獲組(Non-capturing group),表示不返回該組匹配的內(nèi)容,即匹配的結(jié)果中不計(jì)入這個(gè)括號(hào)。
var m = "abc".match(/(?:.)b(.)/); m[1] // "c"
上面代碼中的模式,一共使用了兩個(gè)括號(hào)。其中第一個(gè)括號(hào)是非捕獲組,所以返回的第一個(gè)被捕獲的組是第二個(gè)括號(hào)所匹配的“c”。
下面是用來分解網(wǎng)址的正則表達(dá)式。
var url = /(http|ftp):\/\/([^/\r\n]+)(\/[^\r\n]*)?/; url.exec("http://google.com/"); // ["http://google.com/", "http", "google.com", "/"] var url = /(?:http|ftp):\/\/([^/\r\n]+)(\/[^\r\n]*)?/; url.exec("http://google.com/"); // ["http://google.com/", "google.com", "/"]
上面的代碼中,前一個(gè)正則表達(dá)式是正常匹配,第一個(gè)括號(hào)返回網(wǎng)絡(luò)協(xié)議;后一個(gè)正則表達(dá)式是非捕獲匹配,返回結(jié)果中不包括網(wǎng)絡(luò)協(xié)議。
(3)先行斷言
x(?=y)稱為先行斷言(Positive look-ahead),x只有在y前面才匹配,y不會(huì)被計(jì)入返回結(jié)果。
var m = "abc".match(/b(?=c)/); m // "b"
上面的代碼使用了先行斷言,b在c前面所以被匹配,但是括號(hào)對(duì)應(yīng)的c不會(huì)被返回。
(4)后行斷言
x(?!y)稱為后行斷言(Negative look-ahead),x只有不在y前面才匹配,y不會(huì)被計(jì)入返回結(jié)果。
var m = "abd".match(/b(?!c)/); m // ["b"]
上面的代碼使用了后行斷言,b不在c前面所以被匹配,而且括號(hào)對(duì)應(yīng)的d不會(huì)被返回。
Axel Rauschmayer, JavaScript: an overview of the regular expression API
Mozilla Developer Network, Regular Expressions
Axel Rauschmayer, The flag /g of JavaScript’s regular expressions
Sam Hughes, Learn regular expressions in about 55 minutes