?
Dokumen ini menggunakan Manual laman web PHP Cina Lepaskan
概述
正則對象的屬性和方法
屬性
test方法
exec方法
字符串對象的方法
match方法
search方法
replace方法
split方法
匹配規(guī)則
字面量字符和元字符
字符類
重復(fù)類
量詞符
轉(zhuǎn)義符
修飾符
預(yù)定義模式
特殊字符
組匹配
參考鏈接
正則表達式(regular expression)是一種表達文本模式的方法,常常用作按照“給定模式”匹配文本的工具,比如給定一個Email地址的模式,然后用來確定一個字符串是否為Email地址。JavaScript的正則表達式體系是參照Perl 5建立的。
新建正則表達式有兩種方法。一種是使用字面量,以斜杠表示開始和結(jié)束。
var regex = /xyz/;
另一種是使用RegExp構(gòu)造函數(shù)。
var regex = new RegExp("xyz");
上面兩種寫法是等價的,都建立了一個內(nèi)容為xyz的正則表達式對象。
RegExp構(gòu)造函數(shù)還可以接受第二個參數(shù),表示修飾符(詳細解釋見下文)。
var regex = new RegExp("xyz", "i"); // 等價于 var regex = /xyz/i;
這兩種寫法在運行時有一個細微的區(qū)別。采用字面量的寫法,正則對象在代碼載入時(即編譯時)生成;采用構(gòu)造函數(shù)的方法,正則對象在代碼運行時生成??紤]到書寫的便利和直觀,實際應(yīng)用中,基本上都采用字面量的寫法。
正則對象生成以后,有兩種使用方式:
使用正則對象本身的方法,將字符串作為參數(shù),比如regex.test(string)。
使用字符串對象的方法,將正則對象作為參數(shù),比如string.match(regex)。
下面逐一介紹這兩種使用方式。
正則對象的屬性主要如下:
ignoreCase:返回一個布爾值,表示是否設(shè)置了i修飾符,該屬性只讀。
global:返回一個布爾值,表示是否設(shè)置了g修飾符,該屬性只讀。
lastIndex:返回下一次開始搜索的位置。該屬性可讀寫,但是只在設(shè)置了g修飾符時有意義。
source:返回正則表達式的字符串形式(不包括反斜杠),該屬性只讀。
multiline:返回一個布爾值,表示是否設(shè)置了m修飾符,該屬性只讀。
下面是屬性應(yīng)用的實例。
var r = /abc/igm; r.ignoreCase // true r.global // true r.multiline // true r.lastIndex // 0 r.source // "abc"
test方法返回布爾值,用來驗證字符串是否符合某個模式。
/cat/.test('cats and dogs') // true
上面代碼驗證參數(shù)字符串之中是否包含cat,結(jié)果返回true。
如果正則表達式帶有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
上面代碼的正則對象使用了g修飾符,表示要記錄搜索位置。接著,三次使用test方法,每一次開始搜索的位置都是上一次匹配的后一個位置。
如果正則模式是一個空字符串,則匹配所有字符串。
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方法返回一個數(shù)組,里面是匹配結(jié)果。如果匹配失敗,返回null。
如果正則表示式包含圓括號,則返回的數(shù)組會包括多個元素。其中,第一個元素是整個匹配成功的結(jié)果,后面的元素就是圓括號對應(yīng)的匹配成功的組,也就是說第二個元素就對應(yīng)第一個括號,第三個元素對應(yīng)第二個括號,以此類推。整個返回數(shù)組的length屬性等于匹配成功的組數(shù)+1。
var s = '_x_x'; var r = /_(x)/; r.exec(s) // ["_x", "x"]
上面代碼的exex方法,返回一個數(shù)組。第一個元素是整個匹配的結(jié)果,第二個元素是圓括號匹配的結(jié)果。
exec方法的返回數(shù)組還包含以下兩個屬性:
input:整個原字符串。
index:整個模式匹配成功的開始位置。
var r = /a(b+)a/; var arr = regex.exec("_abbba_aba_"); arr// ["abbba", "bbb"] arr.index// 1 arr.input// "_abbba_aba_"
上面代碼中的index屬性等于1,是因為從原字符串的第二個位置開始匹配成功。
如果正則表達式加上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é)束以后,整個字符串已經(jīng)到達尾部,正則對象的lastIndex屬性重置為0,意味著第四次匹配將從頭開始。
利用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
如果正則對象是一個空字符串,則exec方法會匹配成功,但返回的也是空字符串。
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
字符串對象的方法之中,有4種與正則對象有關(guān)。
match:返回匹配的子字符串。
search:按照給定的正則規(guī)則進行搜索。
replace:按照給定的正則規(guī)則進行替換。
split:按照給定規(guī)則進行字符串分割。
下面逐一介紹。
match方法對字符串進行正則匹配,返回匹配結(jié)果。
var s = '_x_x'; var r1 = /x/; var r2 = /y/; s.match(r1) // ["x"] s.match(r2) // null
從上面代碼可以看到,字符串的match方法與正則對象的exec方法非常類似:匹配成功返回一個數(shù)組,匹配失敗返回null。
如果正則表達式帶有g(shù)修飾符,則該方法與正則對象的exec方法行為不同,會返回所有匹配成功的結(jié)果。
var s = "abba"; var r = /a/g; s.match(r) // ["a", "a"] r.exec(s) // ["a"]
search方法返回第一個滿足條件的匹配結(jié)果在整個字符串中的位置。如果沒有任何匹配,則返回-1。該方法會忽略g參數(shù)。
'_x_x'.search(/x/)// 1
replace方法可以替換匹配的值,它接受兩個參數(shù),第一個是搜索模式,第二個是替換的內(nèi)容。
str.replace(search, replacement)
搜索模式如果不加g修飾符,就替換第一個匹配成功的值,否則替換所有匹配成功的值。
"aaa".replace("a", "b") // "baa" "aaa".replace(/a/, "b") // "baa" "aaa".replace(/a/g, "b") // "bbb"
上面代碼中,最后一個正則表達式使用了g修飾符,導(dǎo)致所有的b都被替換掉了。
replace方法的一個應(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方法的第二個參數(shù)可以使用美元符號$,用來指代所替換的內(nèi)容。
$& 指代匹配的子字符串。
$` 指代匹配結(jié)果前面的文本。
$' 指代匹配結(jié)果后面的文本。
$n 指代匹配成功的第n組內(nèi)容,n是從1的自然數(shù)。
$$ 指代美元符號$。
"hello world".replace(/(\w+)\s(\w+)/,"$2 $1") // "world hello" "abc".replace("b", "[$`-$&-$']") // "a[a-b-c]c"
replace方法的第二個參數(shù)還可以是一個函數(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方法第二個參數(shù)的替換函數(shù),可以接受多個參數(shù)。它的第一個參數(shù)是捕捉到的內(nèi)容,第二個參數(shù)是捕捉到的組匹配(有多少個組匹配,就有多少個對應(yīng)的參數(shù))。此外,最后還可以添加兩個參數(shù),倒數(shù)第二個參數(shù)是捕捉到的內(nèi)容在整個字符串中的位置(比如從第五個位置開始),最后一個參數(shù)是原字符串。下面是一個網(wǎng)頁模板替換的例子。
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; } );
上面代碼的捕捉模式中,有四個括號,所以會產(chǎn)生四個組匹配,在匹配函數(shù)中用$1到$4表示。匹配函數(shù)的作用是將價格插入模板中。
split方法按照正則規(guī)則分割字符串,返回一個由分割后的各個部分組成的數(shù)組。
str.split(separator, [limit])
該方法接受兩個參數(shù),第一個參數(shù)是分隔規(guī)則,第二個參數(shù)是返回數(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' ]
上面代碼使用正則表達式,去除了子字符串的逗號前面的空格。
"aaa*a*".split(/a*/) // [ '', '*', '*' ] "aaa**a*".split(/a*/) // ["", "*", "*", "*"]
上面代碼的分割規(guī)則是出現(xiàn)0次或多次的a,所以第一個分隔符是“aaa”,第二個分割符是“a”,將整個字符串分成三個部分。出現(xiàn)0次的a,意味著只要沒有a就可以分割,實際上就是按字符分割。
如果正則表達式帶有括號,則括號匹配的部分也會作為數(shù)組成員返回。
"aaa*a*".split(/(a*)/) // [ '', 'aaa', '*', 'a', '*' ]
上面代碼的正則表達式使用了括號,第一個組匹配是“aaa”,第二個組匹配是“a”,它們都作為數(shù)組成員返回。
下面是另一個組匹配的例子。
'a, b , '.split(/(,)/) // ["a", ",", " b ", ",", " "] 'a, b , '.split(/ *(,) */) // ["a", ",", "b", ",", ""]
正則表達式對字符串的匹配有很復(fù)雜的規(guī)則。下面一一介紹這些規(guī)則。
大部分字符在正則表達式中,就是字面的含義,比如/a/匹配a,/b/匹配b。它們都叫做“字面量字符”(literal characters)。
/dog/.test("old dog") // true
上面代碼中正則表達式的dog,就是字面量字符,所以/dog/匹配old dog,因為它就表示d、o、g三個字母連在一起。
除了字面量字符以外,還有一部分字符有特殊含義,不代表字面的意思。它們叫做“元字符”(metacharacters),主要有以下幾個。
(1)點字符(.)
點字符(.)匹配除回車(\r)、換行(\n) 、行分隔符(\u2028)和段分隔符(\u2029)以外的所有字符。
/c.t/
上面代碼中的c.t匹配c和t之間包含任意一個字符的情況,只要這三個字符在同一行,比如cat、c2t、c-t等等,但是不匹配coot。
(2)位置字符
位置字符用來提示字符所處的位置,主要有兩個字符。
^ 表示字符串的起首。
$ 表示字符串的行尾。
/^test/.test("test123") // true /test$/.test("new test") // true /^test$/.test("test") // true /^test$/.test("test test") // false
(3)選擇符(|)
豎線符號(|)在正則表達式中表示“或關(guān)系”(OR),即 cat|dog 表示匹配cat或dog。
/11|22/.test("911") // true
字符類(class)表示有一系列字符可供選擇,只要匹配其中一個就可以了。所有可供選擇的字符都放在方括號內(nèi),比如[xyz] 表示x、y、z之中任選一個匹配。
/[abc]/.test("hello world") // false /[abc]/.test("apple") // true
上面代碼表示,字符串hello world不包含abc這三個字母中的任一個,而字符串a(chǎn)pple包含字母a。
有兩個字符在字符類中有特殊含義。
(1)脫字符(^)
如果方括號內(nèi)的第一個字符是[^],則表示除了字符類之中的字符,其他字符都可以匹配。比如,[^xyz] 表示除了x、y、z之外都可以匹配。
/[^abc]/.test("hello world") // true /[^abc]/.test("bbc") // false
上面代碼表示,字符串hello world不包含字母abc中的任一個,所以返回true;字符串bbc不包含abc以外的字母,所以返回false。
如果方括號內(nèi)沒有其他字符,即只有[^],就表示匹配一切字符,其中包括換行符,而點號(.)是不包括換行符的。
var s = 'Please yes\nmake my day!'; s.match(/yes.*day/) // null s.match(/yes[^]*day/) // [ 'yes\nmake my day']
上面代碼中,字符串s含有一個換行符,點號不包括換行符,所以第一個正則表達式匹配失?。坏诙€正則表達式[^]包含一切字符,所以匹配成功。
注意,脫字符只有在字符類的第一個位置才有特殊含義,否則就是字面含義。
(2)連字符(-)
某些情況下,對于連續(xù)序列的字符,連字符(-)用來提供簡寫形式,表示字符的連續(xù)范圍。比如,[abc]可以寫成[a-c],[0123456789]可以寫成[0-9],同理[A-Z]表示26個大寫字母。
/a-z/.test("b") // false /[a-z]/.test("b") // true
上面代碼中,當(dāng)連字號(dash)不出現(xiàn)在方括號之中,就不具備簡寫的作用,只代表字面的含義,所以不匹配字符b。只有當(dāng)連字號用在方括號之中,才表示連續(xù)的字符序列。
以下都是合法的字符類簡寫形式。
[0-9.,] [0-9a-fA-F] [a-zA-Z0-9-] [1-31]
上面代碼中最后一個字符類[1-31],不代表1到31,只代表1到3。
注意,字符類的連字符必須在頭尾兩個字符中間,才有特殊含義,否則就是字面含義。比如,
[-9]
就表示匹配連字符和9,而不是匹配0到9。
連字符還可以用來指定Unicode字符的范圍。
var str = "\u0130\u0131\u0132"; /[\u0128-\uFFFF]/.test(str) // true
另外,不要過分使用連字符,設(shè)定一個很大的范圍,結(jié)果選中意料之外的字符。最典型的例子就是[A-z],表面上它是選中從大寫的A到小寫的z之間52個字母,但是由于在ASCII編碼之中,大寫字母與小寫字母之間還有其他字符,結(jié)果就會出現(xiàn)意料之外的結(jié)果。
/[A-z]/.test('\\') // true
上面代碼中,由于反斜杠(\)的ASCII碼在大寫字母與小寫字母之間,結(jié)果會被選中。
{} 表示模式的重復(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
? 表示某個模式出現(xiàn)1次或0次,等同于{0, 1}。
表示某個模式出現(xiàn)0次或多次,等同于 {0,}。
表示某個模式出現(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
以上三個量詞符,默認情況下的匹配規(guī)則都是貪婪模式,即最大可能匹配,直到下一個字符不滿足匹配規(guī)則為止。比如,對于字符串“aaa”來說,/a+/將會匹配“aaa”,而不會匹配“aa”。為了將貪婪模式改為非貪婪模式,可以在量詞符后面加一個問號,/a+?/將會只匹配“a”。
也就是說,星號(*)和加號(+)還有非貪婪模式的版本。
*?:表示某個模式出現(xiàn)0次或多次,匹配時采用非貪婪模式。
+?:表示某個模式出現(xiàn)1次或多次,匹配時采用非貪婪模式。
正則表達式中那些有特殊含義的字符,如果要匹配它們本身,就需要在它們前面要加上反斜杠。比如要匹配加號,就要寫成+。
/1+1/.test("1+1") // false /1\+1/.test("1+1") // true
正則模式中,需要用斜杠轉(zhuǎn)義的,一共有12個字符:^、.、[、$、(、)、|、*、+、?、{和 \。需要特別注意的是,如果使用RegExp方法生成正則對象,轉(zhuǎn)義需要使用兩個斜杠,因為字符串內(nèi)部會先轉(zhuǎn)義一次。
(new RegExp("1\+1")).test("1+1") // false (new RegExp("1\\+1")).test("1+1") // true
修飾符(modifier)表示模式的附加規(guī)則,放在正則模式的最尾部。
(1)g修飾符
默認情況下,第一次匹配成功后,正則對象就停止向下匹配了。g修飾符表示全局匹配(global),加上它以后,正則對象將匹配全部符合條件的結(jié)果,主要用于搜索和替換。
var regex = /b/; var str = 'abba'; regex.test(str); // true regex.test(str); // true regex.test(str); // true
上面代碼連續(xù)做了三次匹配,都返回true。它的含義是如果不加g修飾符,每次匹配時都是從字符串頭部開始匹配。
var regex = /b/g; var str = 'abba'; regex.test(str); // true regex.test(str); // true regex.test(str); // false
上面代碼中,因為字符串“abba”只有兩個“b”,所以前兩次匹配結(jié)果為true,第三次匹配結(jié)果為false。它的含義是加上g修飾符以后,每次匹配都是從上一次匹配成功處開始往后匹配。
(2)i修飾符
默認情況下,正則對象區(qū)分字母的大小寫,加上i修飾符以后表示忽略大小寫(ignorecase)。
/abc/.test("ABC") // false/abc/i.test("ABC") // true
上面代碼表示,加了i修飾符以后,不考慮大小寫,所以模式abc匹配字符串ABC。
(3)m修飾符
有時,字符串的頭部或尾部可能會有換行符。默認情況下,正則對象會將換行符算入字符串的開頭或結(jié)尾。m修飾符表示多行模式(multiline),加上它以后,正則對象會忽略字符串頭部或尾部的換行符,即^和$會忽略換行符。
/world$/.test("hello world\n") // false /world$/m.test("hello world\n") // true
上面的代碼中,字符串結(jié)尾處有一個換行符。如果不加m修飾符,匹配不成功,因為字符串的結(jié)尾不是world;加上以后,換行符被省略,匹配成功。
修飾符可以多個一起使用。
var regex = /test/ig;
預(yù)定義模式指的是某些常見模式的簡寫方式。
\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
通常,正則表達式遇到換行符(\n)就會停止匹配。
var html = "<b>Hello</b>\n<i>world!</i>"; /.*/.exec(html)[0] // "<b>Hello</b>"
上面代碼中,字符串html包含一個換行符,結(jié)果點字符(.)不匹配換行符,導(dǎo)致匹配結(jié)果可能不符合原意。這時使用\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]
指代一切字符。
正則對象對一些不能打印的特殊字符,提供了表達形式。
\cX 表示 Ctrl-X
[\b] 匹配退格鍵(U+0008),不要與\b混淆。
\n 匹配換行鍵。
\r 匹配回車鍵。
\t 匹配制表符tab(U+0009)。
\v 匹配垂直制表符(U+000B)。
\f 匹配換頁符(U+000C)。
\0 匹配null字符(U+0000)。
\xhh 匹配一個以兩位十六進制數(shù)表示的字符。
\uhhhh 匹配一個以四位十六進制數(shù)表示的unicode字符。
(1)概述
正則表達式的括號表示分組匹配,括號中的模式可以用來捕獲分組的內(nèi)容。
var m = "abcabc".match(/(.)b(.)/); m // ["abc", "a", "c"]
上面代碼中,正則表達式/(.)b(.)/一共使用兩個括號,第一個括號捕獲a,第二個括號捕獲c。
注意,使用組匹配時,不宜同時使用g修飾符,否則match方法不會捕獲分組的內(nèi)容。
var m = "abcabc".match(/(.)b(.)/g); m // ["abc", "abc"]
上面代碼使用帶g修飾符的正則表達式,結(jié)果match方法只捕獲了匹配整個表達式的部分。
在正則表達式內(nèi)部,可以用\n引用括號匹配的內(nèi)容,n是從1開始的自然數(shù),表示對應(yīng)順序的括號。
/(.)b(.)\1b\2/.test("abcabc") // true
上面的代碼中,\1表示前一個括號匹配的內(nèi)容(即“a”),\2表示第二個括號匹配的內(nèi)容(即“b”)。
組匹配非常有用,下面是一個匹配網(wǎng)頁標(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é)果中不計入這個括號。
var m = "abc".match(/(?:.)b(.)/); m[1] // "c"
上面代碼中的模式,一共使用了兩個括號。其中第一個括號是非捕獲組,所以返回的第一個被捕獲的組是第二個括號所匹配的“c”。
下面是用來分解網(wǎng)址的正則表達式。
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", "/"]
上面的代碼中,前一個正則表達式是正常匹配,第一個括號返回網(wǎng)絡(luò)協(xié)議;后一個正則表達式是非捕獲匹配,返回結(jié)果中不包括網(wǎng)絡(luò)協(xié)議。
(3)先行斷言
x(?=y)稱為先行斷言(Positive look-ahead),x只有在y前面才匹配,y不會被計入返回結(jié)果。
var m = "abc".match(/b(?=c)/); m // "b"
上面的代碼使用了先行斷言,b在c前面所以被匹配,但是括號對應(yīng)的c不會被返回。
(4)后行斷言
x(?!y)稱為后行斷言(Negative look-ahead),x只有不在y前面才匹配,y不會被計入返回結(jié)果。
var m = "abd".match(/b(?!c)/); m // ["b"]
上面的代碼使用了后行斷言,b不在c前面所以被匹配,而且括號對應(yīng)的d不會被返回。
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