正則表示式
正則表示式是用於匹配字串中字元組合的模式。在 JavaScript 中,正則表示式也是物件。這些模式與 RegExp 的 exec() 和 test() 方法一起使用,並且與 String 的 match()、matchAll()、replace()、replaceAll()、search() 和 split() 方法一起使用。本章描述 JavaScript 正則表示式。它簡要概述了每個語法元素。有關每個元素的語義的詳細說明,請閱讀 正則表示式 參考。
建立正則表示式
你可以透過兩種方式構造正則表示式
-
使用正則表示式字面量,它由斜槓之間的模式組成,如下所示
jsconst re = /ab+c/;正則表示式字面量在指令碼載入時編譯正則表示式。如果正則表示式保持不變,使用這種方式可以提高效能。
-
或者呼叫
RegExp物件的建構函式,如下所示jsconst re = new RegExp("ab+c");使用建構函式提供正則表示式的執行時編譯。當你知道正則表示式模式會改變,或者你不知道模式並從其他來源(例如使用者輸入)獲取它時,請使用建構函式。
編寫正則表示式模式
正則表示式模式由簡單字元(例如 /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" 中沒有匹配,因為它包含子字串 "ab c",但不包含精確的子字串 "abc"。
使用特殊字元
當搜尋匹配需要不僅僅是直接匹配時,例如查詢一個或多個“b”或查詢空格時,你可以在模式中包含特殊字元。例如,要匹配單個“a”後跟零個或多個“b”,再後跟“c”,你將使用模式 /ab*c/:"b" 後面的 * 表示“前一項出現 0 次或多次”。在字串 "cbbabbbbcdebc" 中,此模式將匹配子字串 "abbbbc"。
以下頁面提供了適合每個類別的不同特殊字元列表,以及描述和示例。
- 斷言指南
-
斷言包括邊界,表示行和單詞的開頭和結尾,以及以某種方式指示可能匹配的其他模式(包括先行斷言、後行斷言和條件表示式)。
- 字元類指南
-
區分不同型別的字元。例如,區分字母和數字。
- 分組和反向引用指南
-
分組將多個模式作為一個整體,捕獲分組在使用正則表示式模式匹配字串時提供額外的子匹配資訊。反向引用引用同一正則表示式中先前捕獲的分組。
- 量詞指南
-
表示要匹配的字元或表示式的數量。
如果你想在一個表中檢視所有可以在正則表示式中使用的特殊字元,請參見以下內容
| 字元 / 構造 | 對應文章 |
|---|---|
[xyz], [^xyz], ., \d, \D, \w, \W, \s, \S, \t, \r, \n, \v, \f, [\b], \0, \cX, \xhh, \uhhhh, \u{hhhh}, x|y |
|
^, $, \b, \B, x(?=y), x(?!y), (?<=y)x, (?<!y)x |
|
(x), (?<Name>x), (?:x), \n, \k<Name> |
|
x*, x+, x?, x{n}, x{n,}, x{n,m} |
注意: 還提供了一個更大的備忘單(僅聚合了這些單獨文章的部分內容)。
轉義
如果你需要字面量使用任何特殊字元(例如,實際搜尋 "*"),你應該在其前面加上反斜槓進行轉義。例如,要搜尋 "a" 後跟 "*" 後跟 "b",你將使用 /a\*b/ —— 反斜槓“轉義”了 "*",使其成為字面量而不是特殊字元。
注意:在許多情況下,當嘗試匹配特殊字元時,你可以將其包裹在字元類中作為轉義的替代方案,例如 /a[*]b/。
類似地,如果你正在編寫正則表示式字面量並且需要匹配斜槓 (“/”),你需要轉義它(否則,它會終止模式)。例如,要搜尋字串 “/example/” 後跟一個或多個字母字元,你將使用 /\/example\/[a-z]+/i—— 每個斜槓前的反斜槓使其成為字面量。
要匹配字面量反斜槓,你需要轉義反斜槓。例如,要匹配字串 "C:\",其中 "C" 可以是任何字母,你將使用 /[A-Z]:\\/ —— 第一個反斜槓轉義它後面的一個,因此表示式搜尋單個字面量反斜槓。
如果使用帶有字串字面量的 RegExp 建構函式,請記住反斜槓在字串字面量中是跳脫字元,因此要在正則表示式中使用它,你需要在字串字面量級別進行轉義。/a\*b/ 和 new RegExp("a\\*b") 建立相同的表示式,它搜尋“a”後跟字面量“*”後跟“b”。
RegExp.escape() 函式返回一個新字串,其中正則表示式語法中的所有特殊字元都已轉義。這允許你執行 new RegExp(RegExp.escape("a*b")) 來建立一個只匹配字串 "a*b" 的正則表示式。
使用括號
正則表示式模式任何部分的括號都會導致記住該部分匹配的子字串。一旦記住,子字串就可以被召回以供其他使用。有關更多詳細資訊,請參閱分組和反向引用。
在 JavaScript 中使用正則表示式
正則表示式與 RegExp 方法 test() 和 exec() 以及 String 方法 match()、matchAll()、replace()、replaceAll()、search() 和 split() 一起使用。
| 方法 | 描述 |
|---|---|
exec() |
在字串中執行搜尋匹配。它返回一個資訊陣列,如果未匹配則返回 null。 |
test() |
測試字串中是否存在匹配項。它返回 true 或 false。 |
match() |
返回一個包含所有匹配項(包括捕獲分組)的陣列,如果未找到匹配項則返回 null。 |
matchAll() |
返回一個包含所有匹配項(包括捕獲分組)的迭代器。 |
search() |
測試字串中是否存在匹配項。它返回匹配項的索引,如果搜尋失敗則返回 -1。 |
replace() |
在字串中執行搜尋匹配,並將匹配的子字串替換為替換子字串。 |
replaceAll() |
在字串中執行搜尋所有匹配項,並將匹配的子字串替換為替換子字串。 |
split() |
使用正則表示式或固定字串將字串拆分為子字串陣列。 |
當你需要知道字串中是否找到模式時,使用 test() 或 search() 方法;如果需要更多資訊(但執行速度較慢),請使用 exec() 或 match() 方法。如果你使用 exec() 或 match() 並且匹配成功,這些方法會返回一個數組並更新關聯的正則表示式物件以及預定義的正則表示式物件 RegExp 的屬性。如果匹配失敗,exec() 方法返回 null(它會轉換為 false)。
在以下示例中,指令碼使用 exec() 方法在字串中查詢匹配項。
const myRe = /d(b+)d/g;
const myArray = myRe.exec("cdbbdbsbz");
如果你不需要訪問正則表示式的屬性,建立 myArray 的另一種方法是使用此指令碼
const myArray = /d(b+)d/g.exec("cdbbdbsbz");
// similar to 'cdbbdbsbz'.match(/d(b+)d/g); however,
// 'cdbbdbsbz'.match(/d(b+)d/g) outputs [ "dbbd" ]
// while /d(b+)d/g.exec('cdbbdbsbz') outputs [ 'dbbd', 'bb', index: 1, input: 'cdbbdbsbz' ]
(有關不同行為的更多資訊,請參閱將全域性搜尋標誌與 exec() 配合使用。)
如果你想從字串構造正則表示式,另一種替代方法是此指令碼
const myRe = new RegExp("d(b+)d", "g");
const myArray = myRe.exec("cdbbdbsbz");
使用這些指令碼,匹配成功並返回陣列並更新下表中顯示的屬性。
| Object | 屬性或索引 | 描述 | 在此示例中 |
|---|---|---|---|
myArray |
匹配的字串和所有記住的子字串。 | ['dbbd', 'bb', index: 1, input: 'cdbbdbsbz'] |
|
index |
匹配項在輸入字串中的 0-based 索引。 | 1 |
|
input |
原始字串。 | 'cdbbdbsbz' |
|
[0] |
上次匹配的字元。 | 'dbbd' |
|
myRe |
lastIndex |
開始下一次匹配的索引。(此屬性僅在正則表示式使用 g 選項時設定,如使用標誌進行高階搜尋中所述。) | 5 |
source |
模式的文字。在正則表示式建立時更新,而不是執行時更新。 | 'd(b+)d' |
如本例的第二種形式所示,你可以使用物件初始化器建立的正則表示式而不將其賦值給變數。但是,如果你這樣做,每次出現都是一個新的正則表示式。因此,如果你不將其賦值給變數就使用這種形式,你就無法隨後訪問該正則表示式的屬性。例如,假設你有以下指令碼
const myRe = /d(b+)d/g;
const myArray = myRe.exec("cdbbdbsbz");
console.log(`The value of lastIndex is ${myRe.lastIndex}`);
// "The value of lastIndex is 5"
但是,如果你有以下指令碼
const 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 屬性具有不同的值。如果你需要訪問使用物件初始化器建立的正則表示式的屬性,你應該首先將其賦值給變數。
使用標誌進行高階搜尋
正則表示式具有可選標誌,允許全域性搜尋和不區分大小寫搜尋等功能。這些標誌可以單獨使用或組合使用,並且是正則表示式的一部分。
| 標誌 | 描述 | 對應屬性 |
|---|---|---|
d |
為子字串匹配生成索引。 | hasIndices |
g |
全域性搜尋。 | global |
i |
不區分大小寫搜尋。 | ignoreCase |
m |
使 ^ 和 $ 匹配每行的開頭和結尾,而不是整個字串的開頭和結尾。 |
multiline |
s |
允許 . 匹配換行符。 |
dotAll |
u |
"Unicode";將模式視為 Unicode 碼點序列。 | unicode |
v |
u 模式的升級版,具有更多 Unicode 功能。 |
unicodeSets |
y |
執行“粘性”搜尋,從目標字串的當前位置開始匹配。 | |
要將標誌包含在正則表示式中,請使用此語法
const re = /pattern/flags;
or
const re = new RegExp("pattern", "flags");
請注意,這些標誌是正則表示式不可或缺的一部分。它們無法在以後新增或刪除。
例如,re = /\w+\s/g 建立一個正則表示式,它查詢一個或多個字元後跟一個空格,並且它在整個字串中查詢此組合。
const re = /\w+\s/g;
const str = "fee fi fo fum";
const myArray = str.match(re);
console.log(myArray);
// ["fee ", "fi ", "fo "]
你可以替換這一行
const re = /\w+\s/g;
with
const re = new RegExp("\\w+\\s", "g");
並獲得相同的結果。
m 標誌用於指定多行輸入字串應被視為多行。如果使用 m 標誌,^ 和 $ 匹配輸入字串中任何行的開頭或結尾,而不是整個字串的開頭或結尾。
i、m 和 s 標誌可以使用修飾符語法針對正則表示式的特定部分啟用或停用。
將全域性搜尋標誌與 exec() 配合使用
帶有 g 標誌的 RegExp.prototype.exec() 方法會迭代地返回每個匹配項及其位置。
const str = "fee fi fo fum";
const re = /\w+\s/g;
console.log(re.exec(str)); // ["fee ", index: 0, input: "fee fi fo fum"]
console.log(re.exec(str)); // ["fi ", index: 4, input: "fee fi fo fum"]
console.log(re.exec(str)); // ["fo ", index: 7, input: "fee fi fo fum"]
console.log(re.exec(str)); // null
相比之下,String.prototype.match() 方法一次返回所有匹配項,但沒有它們的位置。
console.log(str.match(re)); // ["fee ", "fi ", "fo "]
使用 Unicode 正則表示式
u 標誌用於建立“Unicode”正則表示式;也就是說,支援與 Unicode 文字匹配的正則表示式。在 Unicode 模式下啟用的一個重要功能是Unicode 屬性轉義。例如,以下正則表示式可用於匹配任意 Unicode“單詞”
/\p{L}*/u;
Unicode 正則表示式的執行行為也不同。RegExp.prototype.unicode 包含對此的更多解釋。
示例
使用特殊字元驗證輸入
在以下示例中,使用者需要輸入電話號碼。當用戶按下“檢查”按鈕時,指令碼會檢查號碼的有效性。如果號碼有效(匹配正則表示式指定的字元序列),指令碼會顯示一條訊息,感謝使用者並確認號碼。如果號碼無效,指令碼會通知使用者電話號碼無效。
正則表示式查詢
- 資料行的開頭:
^ - 後跟三個數字字元
\d{3}或|一個左括號\(,後跟三個數字\d{3},後跟一個右括號\),在一個非捕獲分組中(?:) - 後跟一個連字元、正斜槓或小數點,在一個捕獲分組中
() - 後跟三個數字
\d{3} - 後跟第一個捕獲分組中記住的匹配項
\1 - 後跟四個數字
\d{4} - 後跟資料行的結尾:
$
HTML
<p>
Enter your phone number (with area code) and then click "Check".
<br />
The expected format is like ###-###-####.
</p>
<form id="form">
<input id="phone" />
<button type="submit">Check</button>
</form>
<p id="output"></p>
JavaScript
const form = document.querySelector("#form");
const input = document.querySelector("#phone");
const output = document.querySelector("#output");
const re = /^(?:\d{3}|\(\d{3}\))([-/.])\d{3}\1\d{4}$/;
function testInfo(phoneInput) {
const ok = re.exec(phoneInput.value);
output.textContent = ok
? `Thanks, your phone number is ${ok[0]}`
: `${phoneInput.value} isn't a phone number with area code!`;
}
form.addEventListener("submit", (event) => {
event.preventDefault();
testInfo(input);
});
結果
工具
- RegExr
-
一個用於學習、構建和測試正則表示式的線上工具。
- 正則表示式測試器
-
一個線上正則表示式構建器/偵錯程式
- 正則表示式互動式教程
-
一個線上互動式教程、備忘單和演練場。
- 正則表示式視覺化器
-
一個線上視覺化正則表示式測試器。