正則表達式是被用來匹配字符串中的字符組合的模式。在JavaScript中,正則表達式也是對象。這種模式能夠被用於 RegExp
的 exec
和 test
方法以及 String
的 match
、replace
、search
和 split
方法。本章介紹的是 Javascript 的正則表達式。javascript
你能夠經過下面兩種方法建立一個正則表達式:html
使用一個正則表達式字面量,以下所示:java
var re = /ab+c/;
正則表達式字面量在腳本加載後編譯。若你的正則表達式是常量,使用這種方式能夠得到更好的性能。git
調用RegExp
對象的構造函數,以下所示:正則表達式
var re = new RegExp("ab+c");
使用構造函數,提供了對正則表達式運行時的編譯。當你知道正則表達式的模式會發生改變, 或者你事先並不瞭解它的模式或者是從其餘地方(好比用戶的輸入),獲得的代碼這時比較適合用構造函數的方式。express
一個正則表達式模式是由簡單的字符所構成的,好比/abc/
, 或者是簡單和特殊字符的組合,好比/ab*c/
或 /Chapter (\d+)\.\d*/。後者
用到了括號,它在正則表達式中能夠被用作是一個記憶設備。這一部分正則所匹配的字符將會被記住,在後面能夠被利用。正如 使用括號的子字符串匹配數組
簡單的模式是有你找到的直接匹配所構成的。好比,/abc/
這個模式就匹配了在一個字符串中,僅僅字符 'abc' 同時出現並按照這個順序。在 "Hi, do you know your abc's?" 和 "The latest airplane designs evolved from slabcraft." 就會匹配成功。在上面的兩個實例中,匹配的是子字符串 'abc'。在字符串 "Grab crab" 中將不會被匹配,由於它不包含任何的 'abc' 子字符串。app
當你須要搜索一個比直接匹配須要更多條件的匹配時,好比尋找一個或多個 'b',或者尋找空格,那麼這時模式將要包含特殊字符。好比, 模式/ab*c/
匹配了一個單獨的 'a' 後面跟了零個或則多個 'b'(*的意思是前面一項出現了零個或者多個),且後面跟着 'c' 的任何字符組合。在字符串 "cbbabbbbcdebc" 中,這個模式匹配了子字符串 "abbbbc"。ide
下面的表格列出了一個咱們在正則表達式中能夠利用的特殊字符的完整列表和描述。函數
字符 | 含義 |
---|---|
\ |
匹配將依照下列規則: 反斜槓,對於其後的日常被看成字面量的字符,將其轉義爲特殊字符。好比,/b/匹配了字符'b'.經過在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" 中的 'boooo' 和 "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"。 還能夠運用於向前斷言,在本表格的 x(?=y) 和 x(?!y) 中有描述。 |
. |
(小數點)匹配除了換行符( 例如,/.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 匹配字符串的後兩個單詞。注意 \一、\二、\n 是用在正則表達式的匹配環節。在正則表達式的替換環節,則要使用像 $一、$二、$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/將不能匹配任何字符串,由於一個單詞中的字符永遠也不可能被一個非詞彙字符和一個詞彙字符同時緊跟着。 |
\B |
匹配一個非單詞邊界。他匹配一個先後字符都是相同類型的位置:都是單詞或者都不是單詞。一個字符串的開始和結尾都被認爲是非單詞。 例如,/\B../匹配"noonday"中得'oo', 而/y\B./匹配"possibly yesterday"中得’ye‘ |
\cX |
當X是處於A到Z之間的字符的時候,匹配字符串中的一個控制符。 當X是處於A到Z之間的字符的時候,匹配字符串中的一個控制符。 例如, |
\d |
匹配一個數字
例如, |
\D |
匹配一個非數字字符
例如, |
\f |
匹配一個換頁符 (U+000C)。 |
\n |
匹配一個換行符 (U+000A)。 |
\r |
匹配一個回車符 (U+000D)。 |
\s |
匹配一個空白字符,包括空格、製表符、換頁符和換行符。 等價於 例如, |
\S |
匹配一個非空白字符。 等價於 例如, |
\t |
匹配一個水平製表符 (U+0009)。 |
\v |
匹配一個垂直製表符 (U+000B)。 |
\w |
匹配一個單字字符(字母、數字或者下劃線)。 等價於 例如, |
\W |
匹配一個非單字字符。 等價於 例如, |
\n |
當 n 是一個正整數,一個返回引用到最後一個與有n插入的正值表達式(counting left parentheses)匹配的副字符串。 好比 |
\0 |
匹配 NULL (U+0000) 字符, 不要在這後面跟其它小數,由於 \0<digits> 是一個八進制轉義序列。 |
\xhh |
匹配帶有兩位小數代碼(hh)的字符 |
\uhhhh |
匹配帶有四位小數代碼(hh)的字符 |
有些轉義用戶輸入被處理成含有一個正值表達式的字面字符串,這些輸入能夠被簡單的替代值補充完整。
function escapeRegExp(string){ return string.replace(/([.*+?^=!:${}()|[\]\/\\])/g, "\\$&"); //$&表示被匹配的字符串 }
任何正值表達式的插入語都會使這部分匹配的副字符串被記憶。一旦被記憶,這個副字符串就能夠被調用於其它用途,如同 使用括號的子字符串匹配之中所述。
好比, /Chapter (\d+)\.\d*/
解釋了額外轉義的和特殊的字符,並說明了這部分pattern應該被記憶。它精確地匹配後面跟着一個以上數字字符的字符 'Chapter ' (\d
意爲任何數字字符,+ 意爲1次以上
),跟着一個小數點(在這個字符中自己也是一個特殊字符;小數點前的 \ 意味着這個pattern必須尋找字面字符 '.'),跟着任何數字字符0次以上。 (\d
意爲數字字符, *
意爲0次以上)。另外,插入語也用來記憶第一個匹配的數字字符。
此模式能夠匹配字符串"Open Chapter 4.3, paragraph 6",而且'4'將會被記住。此模式並不能匹配"Chapter 3 and 4",由於在這個字符串中'3'的後面沒有點號'.'。
括號中的"?:",這種模式匹配的子字符串將不會被記住。好比,(?:\d+)匹配一次或屢次數字字符,可是不能記住匹配的字符。
正則表達式能夠被用於RegExp
的exec
和test
方法以及 String
的match
、replace
、search
和split
方法。這些方法在JavaScript 手冊中有詳細的解釋。
方法 | 描述 |
---|---|
exec |
一個在字符串中執行查找匹配的RegExp方法,它返回一個數組(未匹配到則返回null)。 |
test |
一個在字符串中測試是否匹配的RegExp方法,它返回true或false。 |
match |
一個在字符串中執行查找匹配的String方法,它返回一個數組或者在未匹配到時返回null。 |
search |
一個在字符串中測試匹配的String方法,它返回匹配到的位置索引,或者在失敗時返回-1。 |
replace |
一個在字符串中執行查找匹配的String方法,而且使用替換字符串替換掉匹配到的子字符串。 |
split |
一個使用正則表達式或者一個固定字符串分隔一個字符串,並將分隔後的子字符串存儲到數組中的String方法。 |
當你想要知道在一個字符串中的一個匹配是否被找到,你可使用test或search方法;想獲得更多的信息(可是比較慢)則可使用exec或match方法。若是你使用exec或match方法而且匹配成功了,那麼這些方法將返回一個數組而且更新相關的正則表達式對象的屬性和預約義的正則表達式對象(詳見下)。若是匹配失敗,那麼exec方法返回null(也就是false)。
在接下來的例子中,腳本將使用exec方法在一個字符串中查找一個匹配。
var myRe = /d(b+)d/g; var myArray = myRe.exec("cdbbdbsbz");
若是你不須要訪問正則表達式的屬性,這個腳本經過另外一個方法來建立myArray:
var myArray = /d(b+)d/g.exec("cdbbdbsbz");
若是你想經過一個字符串構建正則表達式,那麼這個腳本還有另外一種方法:
var myRe = new RegExp("d(b+)d", "g"); var myArray = myRe.exec("cdbbdbsbz");
經過這些腳本,匹配成功後將返回一個數組而且更新正則表達式的屬性,以下表所示。
對象 | 屬性或索引 | 描述 | 在例子中對應的值 |
---|---|---|---|
myArray |
匹配到的字符串和全部被記住的子字符串。 | ["dbbd", "bb"] |
|
index |
在輸入的字符串中匹配到的以0開始的索引值。 | 1 |
|
input |
初始字符串。 | "cdbbdbsbz" |
|
[0] |
匹配到的全部字符串(並非匹配後記住的字符串)。注:原文"The last matched characters.",應該是原版錯誤。匹配到的最後一個字符索引。 | "dbbd" |
|
myRe |
lastIndex |
下一個匹配的索引值。(這個屬性只有在使用g參數時可用在 經過參數進行高級搜索 一節有詳細的描述.) | 5 |
source |
模式文本。在正則表達式建立時更新,不執行。 | "d(b+)d" |
在這個例子中如第二種形式所示,你可使用一個正則表達式建立一個沒有分配給變量的對象初始化容器。若是你這樣作,那麼,每一次使用時都比如在使用一個新的正則表達式。由於這個緣由,若是你使用這個未分配給一個變量的正則表達式,你將在隨後不能訪問這個正則表達式的屬性。例如,假如你有以下腳本:
var myRe = /d(b+)d/g; var myArray = myRe.exec("cdbbdbsbz"); console.log("The value of lastIndex is " + myRe.lastIndex);
這個腳本輸出以下:
The value of lastIndex is 5
然而,若是你有以下腳本:
var myArray = /d(b+)d/g.exec("cdbbdbsbz"); console.log("The value of lastIndex is " + /d(b+)d/g.lastIndex);
它顯示爲:
The value of lastIndex is 0
當發生/d(b+)d/g使用兩個不一樣狀態的正則表達式對象,lastIndex屬性會獲得不一樣的值。若是你須要訪問一個正則表達式的屬性,則須要建立一個對象初始化生成器,你應該首先把它賦值給一個變量。
一個正則表達式模式使用括號,將致使相應的子匹配被記住。例如,/a(b)c /能夠匹配字符串「abc」,而且記得「b」。回調這些括號中匹配的子串,使用數組元素[1],……[n]。
使用括號匹配的子字符串的數量是無限的。返回的數組中保存全部被發現的子匹配。下面的例子說明了如何使用括號的子字符串匹配。
下面的腳本使用replace()方法來轉換字符串中的單詞。在匹配到的替換文本中,腳本使用替代的$ 1,$ 2表示第一個和第二個括號的子字符串匹配。
var re = /(\w+)\s(\w+)/; var str = "John Smith"; var newstr = str.replace(re, "$2, $1"); console.log(newstr);
這個表達式輸出 "Smith, John"。
正則表達式有四個可選參數進行全局和不分大小寫搜索。這些參數既能夠單獨使用也能夠一塊兒使用在任何順序和包含正則表達式的部分中。
標誌 | 描述 |
---|---|
g |
全局搜索。 |
i | 不區分大小寫搜索。 |
m | 多行搜索。 |
y | 執行「粘性」搜索,匹配從目標字符串的當前位置開始,可使用y標誌。 |
包含一個標誌的正則表達式,使用這個表達式:
var re = /pattern/flags;
或者
var re = new RegExp("pattern", "flags");
值得注意的是,標誌時一個正則表達式的一部分,它們在接下來的時間將不能添加或刪除。
例如,re = /\w+\s/g 將建立一個查找一個或多個字符後有一個空格的正則表達式,或者組合起來像此要求的字符串。
var re = /\w+\s/g; var str = "fee fi fo fum"; var myArray = str.match(re); console.log(myArray);
這段代碼將輸出 ["fee ", "fi ", "fo "]。在這個例子中,你能夠將:
var re = /\w+\s/g;
替換成:
var re = new RegExp("\\w+\\s", "g");
而且能獲取到相同的結果。
m標誌用於指定多行輸入字符串應該被視爲多個行。若是使用m標誌,^和$匹配的開始或結束輸入字符串中的每一行,而不是整個字符串的開始或結束。
如下例子說明了一些正值表達式的用途。
如下例子解釋了正值表達式的構成和string.split()
以及 string.replace()的用途。它會整理一個只有粗略格式的含有全名(名字首先出現)的輸入字符串,這個字符串被空格、換行符和一個分號分隔。
最終,它會顛倒名字順序(姓氏首先出現)和list的類型。
// The name string contains multiple spaces and tabs, // and may have multiple spaces between first and last names. var names = "Harry Trump ;Fred Barney; Helen Rigby ; Bill Abel ; Chris Hand "; var output = ["---------- Original String\n", names + "\n"]; // Prepare two regular expression patterns and array storage. // Split the string into array elements. // pattern: possible white space then semicolon then possible white space var pattern = /\s*;\s*/; // Break the string into pieces separated by the pattern above and // store the pieces in an array called nameList var nameList = names.split(pattern); // new pattern: one or more characters then spaces then characters. // Use parentheses to "memorize" portions of the pattern. // The memorized portions are referred to later. pattern = /(\w+)\s+(\w+)/; // New array for holding names being processed. var bySurnameList = []; // Display the name array and populate the new array // with comma-separated names, last first. // // The replace method removes anything matching the pattern // and replaces it with the memorized string—second memorized portion // followed by comma space followed by first memorized portion. // // The variables $1 and $2 refer to the portions // memorized while matching the pattern. output.push("---------- After Split by Regular Expression"); var i, len; for (i = 0, len = nameList.length; i < len; i++){ output.push(nameList[i]); bySurnameList[i] = nameList[i].replace(pattern, "$2, $1"); } // Display the new array. output.push("---------- Names Reversed"); for (i = 0, len = bySurnameList.length; i < len; i++){ output.push(bySurnameList[i]); } // Sort by last name, then display the sorted array. bySurnameList.sort(); output.push("---------- Sorted"); for (i = 0, len = bySurnameList.length; i < len; i++){ output.push(bySurnameList[i]); } output.push("---------- End"); console.log(output.join("\n"));
在如下例子中,咱們指望用戶輸入一個電話號碼。當用戶點擊「Check」按鈕,咱們的腳本開始檢查這些數字是否合法。若是數字合法(匹配正值表達式所規定的字符序列),腳本顯示一條感謝用戶的信息並確認該數字。若是這串數字不合法,腳本提示用戶電話號碼不合法。.
包含非捕獲插入語 (?:
,這個正值表達式尋找三個數字字符\d{3}
OR |
a left parenthesis \(
跟着三位小數 \d{3}
, 跟着一個封閉插入語 \)
, (結束非捕獲插入語 )
), 跟着一個右斜槓或左斜槓或小數點;當它找到三個數字字符,記憶字符 ([-\/\.]),跟着三位小數
\d{3},跟着記住的左斜槓、右斜槓或小數點
\1,跟着四位小數
\d{4}。
當用戶按下Enter設置RegExp.input,這些變化也能被激活。
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <meta http-equiv="Content-Script-Type" content="text/javascript"> <script type="text/javascript"> var re = /\(?\d{3}\)?([-\/\.])\d{3}\1\d{4}/; function testInfo(phoneInput){ var OK = re.exec(phoneInput.value); if (!OK) window.alert(RegExp.input + " isn't a phone number with area code!"); else window.alert("Thanks, your phone number is " + OK[0]); } </script> </head> <body> <p>Enter your phone number (with area code) and then click "Check". <br>The expected format is like ###-###-####.</p> <form action="#"> <input id="phone"><button onclick="testInfo(document.getElementById('phone'));">Check</button> </form> </body> </html>