正則表達式是用於匹配字符串中字符組合的模式
創建正則表達式的方法有兩種,一種是字面量形式,另一種是使用RegExp構造函數:
1 /** 2 * 字面量形式: var expression = / pattern / flags; 3 * flags有如下標志: 4 * g: 全局搜索,應用於所有字符串,而非在發現第一個匹配項停止。 5 * i: 不區分大小寫搜索。 6 * m: 多行搜索。 7 * y: 執行“粘性”搜索,匹配從目標字符串的當前位置開始,可以使用y標志。 8 */ 9 10 var pattern1 = /mader/gi; 11 12 13 /** 14 * RegExp構造函數形式: var re = new RegExp("pattern", "flags"); 15 */ 16 17 var pattern2 = new RegExp('mader', 'gi');
使用簡單模式:
如 /mader/,在字符串“what is 'mader'?”中mader就會匹配成功,而在“what is ‘madre’?”就不會匹配到
使用特殊字符:比如要在字符串中查找有多個‘b’的,比如模式/nb*a/,匹配了一個單獨的 'n' 后面跟了零個或者多個 'b'(*的意思是前面一項出現了零個或者多個)后面跟了a的組合,比如在字符串“hhhhnbbbaNNN”中就會匹配到“nbbba”。
所有特殊字符匹配如下表:
下表來自官方文檔:
字符 | 含義 |
---|---|
\ |
匹配將依照下列規則: 在非特殊字符之前的反斜杠表示下一個字符是特殊的,不能從字面上解釋。例如,沒有前面'\'的'b'通常匹配小寫'b',無論它們出現在哪里。如果加了'\',這個字符變成了一個特殊意義的字符,意思是匹配一個字符邊界。 反斜杠也可以將其后的特殊字符,轉義為字面量。例如,模式 /a*/ 代表會匹配 0 個或者多個 a。相反,模式 /a\*/ 將 '*' 的特殊性移除,從而可以匹配像 "a*" 這樣的字符串。 使用 new RegExp("pattern") 的時候不要忘記將 \ 進行轉義,因為 \ 在字符串里面也是一個轉義字符。 |
^ |
匹配輸入的開始。如果多行標志被設置為true,那么也匹配換行符后緊跟的位置。 例如,/^A/ 並不會匹配 "an A" 中的 'A',但是會匹配 "An E" 中的 'A'。 當 '^' 作為第一個字符出現在一個字符集合模式時,它將會有不同的含義。補充字符集合 一節有詳細介紹和示例。 |
$ |
匹配輸入的結束。如果多行標示被設置為true,那么也匹配換行符前的位置。 例如,/t$/ 並不會匹配 "eater" 中的 't',但是會匹配 "eat" 中的 't'。 |
* |
匹配前一個表達式0次或多次。等價於 {0,}。 例如,/bo*/會匹配 "A ghost boooooed" 中的 'booooo' 和 "A bird warbled" 中的 'b',但是在 "A goat grunted" 中將不會匹配任何東西。 |
+ |
匹配前面一個表達式1次或者多次。等價於 {1,}。 例如,/a+/匹配了在 "candy" 中的 'a',和在 "caaaaaaandy" 中所有的 'a'。 |
? |
匹配前面一個表達式0次或者1次。等價於 {0,1}。 例如,/e?le?/ 匹配 "angel" 中的 'el',和 "angle" 中的 'le' 以及"oslo' 中的'l'。 如果緊跟在任何量詞 *、 +、? 或 {} 的后面,將會使量詞變為非貪婪的(匹配盡量少的字符),和缺省使用的貪婪模式(匹配盡可能多的字符)正好相反。 例如,對 "123abc" 應用 /\d+/ 將會返回 "123",如果使用 /\d+?/,那么就只會匹配到 "1"。 還可以運用於先行斷言,如本表的 |
. |
(小數點)匹配除換行符之外的任何單個字符。 例如,/.n/將會匹配 "nay, an apple is on the tree" 中的 'an' 和 'on',但是不會匹配 'nay'。 |
(x) |
匹配 'x' 並且記住匹配項,就像下面的例子展示的那樣。括號被稱為 捕獲括號。 模式 /(foo) (bar) \1 \2/ 中的 '(foo)' 和 '(bar)' 匹配並記住字符串 "foo bar foo bar" 中前兩個單詞。模式中的 \1 和 \2 匹配字符串的后兩個單詞。注意 \1、\2、\n 是用在正則表達式的匹配環節。在正則表達式的替換環節,則要使用像 $1、$2、$n 這樣的語法,例如,'bar foo'.replace( /(...) (...)/, '$2 $1' )。 |
(?:x) |
匹配 'x' 但是不記住匹配項。這種叫作非捕獲括號,使得你能夠定義為與正則表達式運算符一起使用的子表達式。來看示例表達式 /(?:foo){1,2}/。如果表達式是 /foo{1,2}/,{1,2}將只對 ‘foo’ 的最后一個字符 ’o‘ 生效。如果使用非捕獲括號,則{1,2}會匹配整個 ‘foo’ 單詞。 |
x(?=y) |
匹配'x'僅僅當'x'后面跟着'y'.這種叫做正向肯定查找。 例如,/Jack(?=Sprat)/會匹配到'Jack'僅僅當它后面跟着'Sprat'。/Jack(?=Sprat|Frost)/匹配‘Jack’僅僅當它后面跟着'Sprat'或者是‘Frost’。但是‘Sprat’和‘Frost’都不是匹配結果的一部分。 |
x(?!y) |
匹配'x'僅僅當'x'后面不跟着'y',這個叫做正向否定查找。 例如,/\d+(?!\.)/匹配一個數字僅僅當這個數字后面沒有跟小數點的時候。正則表達式/\d+(?!\.)/.exec("3.141")匹配‘141’但是不是‘3.141’ |
x|y |
匹配‘x’或者‘y’。 例如,/green|red/匹配“green apple”中的‘green’和“red apple”中的‘red’ |
{n} |
n是一個正整數,匹配了前面一個字符剛好發生了n次。 比如,/a{2}/不會匹配“candy”中的'a',但是會匹配“caandy”中所有的a,以及“caaandy”中的前兩個'a'。 |
{n,m} |
n 和 m 都是整數。匹配前面的字符至少n次,最多m次。如果 n 或者 m 的值是0, 這個值被忽略。 例如,/a{1, 3}/ 並不匹配“cndy”中得任意字符,匹配“candy”中得a,匹配“caandy”中得前兩個a,也匹配“caaaaaaandy”中得前三個a。注意,當匹配”caaaaaaandy“時,匹配的值是“aaa”,即使原始的字符串中有更多的a。 |
[xyz] |
一個字符集合。匹配方括號的中任意字符,包括轉義序列。你可以使用破折號(-)來指定一個字符范圍。對於點(.)和星號(*)這樣的特殊符號在一個字符集中沒有特殊的意義。他們不必進行轉義,不過轉義也是起作用的。 例如,[abcd] 和[a-d]是一樣的。他們都匹配"brisket"中得‘b’,也都匹配“city”中的‘c’。/[a-z.]+/ 和/[\w.]+/都匹配“test.i.ng”中得所有字符。 |
[^xyz] |
一個反向字符集。也就是說, 它匹配任何沒有包含在方括號中的字符。你可以使用破折號(-)來指定一個字符范圍。任何普通字符在這里都是起作用的。 例如,[^abc] 和 [^a-c] 是一樣的。他們匹配"brisket"中得‘r’,也匹配“chop”中的‘h’。 |
[\b] |
匹配一個退格(U+0008)。(不要和\b混淆了。) |
\b |
匹配一個詞的邊界。一個詞的邊界就是一個詞不被另外一個詞跟隨的位置或者不是另一個詞匯字符前邊的位置。注意,一個匹配的詞的邊界並不包含在匹配的內容中。換句話說,一個匹配的詞的邊界的內容的長度是0。(不要和[\b]混淆了) 例子: /\bm/匹配“moon”中得‘m’; /oo\b/並不匹配"moon"中得'oo',因為'oo'被一個詞匯字符'n'緊跟着。 /oon\b/匹配"moon"中得'oon',因為'oon'是這個字符串的結束部分。這樣他沒有被一個詞匯字符緊跟着。 /\w\b\w/將不能匹配任何字符串,因為一個單詞中的字符永遠也不可能被一個非詞匯字符和一個詞匯字符同時緊跟着。 注意: JavaScript的正則表達式引擎將特定的字符集定義為“字”字符。不在該集合中的任何字符都被認為是一個斷詞。這組字符相當有限:它只包括大寫和小寫的羅馬字母,小數位數和下划線字符。不幸的是,重要的字符,例如“é”或“ü”,被視為斷詞。 |
\B |
匹配一個非單詞邊界。他匹配一個前后字符都是相同類型的位置:都是單詞或者都不是單詞。一個字符串的開始和結尾都被認為是非單詞。 例如,/\B../匹配"noonday"中得'oo', 而/y\B./匹配"possibly yesterday"中得’ye‘ |
\cX |
當X是處於A到Z之間的字符的時候,匹配字符串中的一個控制符。 例如, |
\d |
匹配一個數字
例如, |
\D |
匹配一個非數字字符
例如, |
\f |
匹配一個換頁符 (U+000C)。 |
\n |
匹配一個換行符 (U+000A)。 |
\r |
匹配一個回車符 (U+000D)。 |
\s |
匹配一個空白字符,包括空格、制表符、換頁符和換行符。 等價於[ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]。 例如, |
\S |
匹配一個非空白字符。 等價於 例如, |
\t |
匹配一個水平制表符 (U+0009)。 |
\v |
匹配一個垂直制表符 (U+000B)。 |
\w |
匹配一個單字字符(字母、數字或者下划線)。 等價於 例如, |
\W |
匹配一個非單字字符。 等價於 例如, |
\n |
當 n 是一個正整數,一個返回引用到最后一個與有n插入的正值表達式(counting left parentheses)匹配的副字符串。 比如 |
\0 |
匹配 NULL (U+0000) 字符, 不要在這后面跟其它小數,因為 \0<digits> 是一個八進制轉義序列。 |
\xhh |
與代碼 hh 匹配字符(兩個十六進制數字) |
\uhhhh |
與代碼 hhhh 匹配字符(四個十六進制數字)。 |
正則表達式有如下方法:
exec 一個在字符串中執行查找匹配的RegExp方法,它返回一個數組(未匹配到則返回null)。
test 一個在字符串中測試是否匹配的RegExp方法,它返回true或false。
match 一個在字符串中執行查找匹配的String方法,它返回一個數組或者在未匹配到時返回null。
search 一個在字符串中測試匹配的String方法,它返回匹配到的位置索引,或者在失敗時返回-1。
replace 一個在字符串中執行查找匹配的String方法,並且使用替換字符串替換掉匹配到的子字符串。
split 一個使用正則表達式或者一個固定字符串分隔一個字符串,並將分隔后的子字符串存儲到數組中的String方法。
為什么有時候對於同一個字符串和同一個正則表達式,有時匹配成功,有時匹配失敗呢?
1 var pattern = /cat/g; 2 var str = "It's a cat"; 3 console.log(pattern.test(str)); //返回true 4 console.log(pattern.test(str)); //返回false 5 /**對於flag:g全局模式,當第一次匹配成功后,下一次匹配就會從匹配成功的字符串的下一個字符的索引開始,而不是從字符串的頭部開始**/ 6 7 var pattern = /cat/g; 8 var str = "It's a cat"; 9 console.log(pattern.test(str)); //返回true 10 str = "It's an cat"; 11 console.log(pattern.test(str)); //返回false 12 /**如上,修改完字符串后,返回的依然是false,因為全局搜索g會保存一個lastIndex保存着上一次匹配到的索引,可以通過pattern.lastIndex查看**/
正則表達式字面量始終共享一個RegExp實例,而使用構造函數創建的每一個新RegExp實例都是一個新實例
var re = null,i; for( i=0; i<10; i++){ re = /cat/g; re.test("I't a cat or a dog"); } for( i=0; i<10; i++){ re = new RegExp("cat", "g"); re.test("I't a cat or a dog"); } /**第一個循環中,第一次調用時匹配成功,第二次失敗**/ /**第二個循環中,每次調用test()都會返回true**/ /**所以,在使用正則表達式字面量時,每次都要創建一個新的RegExp實例**/