方括號 […]
內的幾個字元或字元類別表示「搜尋給定字元中的任何字元」。
集合
例如,[eao]
表示 3 個字元中的任何一個:'a'
、'e'
或 'o'
。
這稱為集合。集合可以用在正規表示法中,搭配一般字元使用
// find [t or m], and then "op"
alert( "Mop top".match(/[tm]op/gi) ); // "Mop", "top"
請注意,儘管集合中有多個字元,但它們在配對中只對應到一個字元。
因此,以下範例不會產生配對
// find "V", then [o or i], then "la"
alert( "Voila".match(/V[oi]la/) ); // null, no matches
此模式搜尋
V
,- 然後是字母
[oi]
中的一個, - 然後是
la
。
因此會找到 Vola
或 Vila
的相符項。
範圍
方括號也可能包含字元範圍。
例如,[a-z]
是從 a
到 z
範圍內的字元,而 [0-5]
是從 0
到 5
範圍內的數字。
在以下範例中,我們搜尋的是 "x"
後面接著兩個從 A
到 F
的數字或字母
alert( "Exception 0xAF".match(/x[0-9A-F][0-9A-F]/g) ); // xAF
這裡的 [0-9A-F]
有兩個範圍:它搜尋的字元可能是從 0
到 9
範圍內的數字,或從 A
到 F
範圍內的字母。
如果我們也想要搜尋小寫字母,我們可以加入 a-f
範圍:[0-9A-Fa-f]
。或加入 i
旗標。
我們也可以在 […]
內使用字元類別。
例如,如果我們想要搜尋一個字元 \w
或連字號 -
,那麼這個集合就是 [\w-]
。
也可以結合多個類別,例如 [\s\d]
表示「空白字元或數字」。
例如
- \d – 與
[0-9]
相同, - \w – 與
[a-zA-Z0-9_]
相同, - \s – 與
[\t\n\v\f\r ]
相同,外加一些其他較少見的 Unicode 空白字元。
範例:多語言 \w
由於字元類別 \w
是 [a-zA-Z0-9_]
的簡寫,因此它無法找到中文象形文字、西里爾字母等。
我們可以寫一個更通用的模式,用來搜尋任何語言中的字元。這可以使用 Unicode 屬性輕鬆達成:[\p{Alpha}\p{M}\p{Nd}\p{Pc}\p{Join_C}]
。
讓我們解讀一下。類似於 \w
,我們建立了一個自己的集合,其中包含具有以下 Unicode 屬性的字元
Alphabetic
(Alpha
) – 字母,Mark
(M
) – 重音,Decimal_Number
(Nd
) – 數字,Connector_Punctuation
(Pc
) – 底線'_'
和類似字元,Join_Control
(Join_C
) – 兩個特殊代碼200c
和200d
,用於連字,例如阿拉伯語。
使用範例
let regexp = /[\p{Alpha}\p{M}\p{Nd}\p{Pc}\p{Join_C}]/gu;
let str = `Hi 你好 12`;
// finds all letters and digits:
alert( str.match(regexp) ); // H,i,你,好,1,2
當然,我們可以編輯這個模式:新增 Unicode 屬性或移除它們。Unicode 屬性在文章 Unicode: flag "u" and class \p{...} 中有更詳細的說明。
Unicode 屬性 p{…}
在 IE 中未實作。如果我們真的需要它們,可以使用函式庫 XRegExp。
或僅使用我們感興趣的語言中的字元範圍,例如 [а-я]
表示西里爾字母。
排除範圍
除了正常的範圍之外,還有看起來像 [^…]
的「排除」範圍。
它們在開頭用插入符號 ^
表示,並與除了給定字元之外的任何字元相符。
例如
[^aeyo]
– 任何字元,除了'a'
、'e'
、'y'
或'o'
。[^0-9]
– 任何字元,除了數字,與\D
相同。[^\s]
– 任何非空白字元,與\S
相同。
以下範例尋找任何字元,除了字母、數字和空白
alert( "[email protected]".match(/[^\d\sA-Z]/gi) ); // @ and .
在 […] 中跳脫
通常當我們想要精確地找到一個特殊字元時,我們需要像 \.
一樣跳脫它。如果我們需要反斜線,則使用 \\
,依此類推。
在方括號中,我們可以在不跳脫的情況下使用絕大多數特殊字元
- 符號
. + ( )
永遠不需要跳脫。 - 連字元
-
在開頭或結尾(它不定義範圍的地方)不會跳脫。 - 插入符號
^
僅在開頭(表示排除)時跳脫。 - 閉合方括號
]
總是跳脫(如果我們需要尋找該符號)。
換句話說,除了方括號的意義之外,所有特殊字元都可以在不跳脫的情況下使用。
方括號內的句點 .
僅表示句點。模式 [.,]
會尋找其中一個字元:句點或逗號。
在以下範例中,正規表示式 [-().^+]
尋找其中一個字元 -().^+
// No need to escape
let regexp = /[-().^+]/g;
alert( "1 + 2 - 3".match(regexp) ); // Matches +, -
…但如果你決定「以防萬一」跳脫它們,那不會有任何害處
// Escaped everything
let regexp = /[\-\(\)\.\^\+]/g;
alert( "1 + 2 - 3".match(regexp) ); // also works: +, -
範圍和旗標「u」
如果集合中有代理對,則需要旗標 u
才能正確運作。
例如,讓我們在字串 𝒳
中尋找 [𝒳𝒴]
alert( '𝒳'.match(/[𝒳𝒴]/) ); // shows a strange character, like [?]
// (the search was performed incorrectly, half-character returned)
結果不正確,因為預設正規表示式「不知道」代理對。
正規表示式引擎認為 [𝒳𝒴]
– 不是兩個,而是四個字元
𝒳
的左半邊(1)
,𝒳
的右半邊(2)
,𝒴
(3)
的左半邊𝒴
(4)
的右半邊
我們可以看到它們的程式碼如下
for(let i=0; i<'𝒳𝒴'.length; i++) {
alert('𝒳𝒴'.charCodeAt(i)); // 55349, 56499, 55349, 56500
};
因此,上面的範例會找到並顯示 𝒳
的左半邊
如果我們新增旗標 u
,則行為會正確
alert( '𝒳'.match(/[𝒳𝒴]/u) ); // 𝒳
在尋找範圍(例如 [𝒳-𝒴]
)時,會發生類似的狀況
如果我們忘記新增旗標 u
,就會發生錯誤
'𝒳'.match(/[𝒳-𝒴]/); // Error: Invalid regular expression
原因是沒有旗標 u
,代理對會被視為兩個字元,因此 [𝒳-𝒴]
會被解釋為 [<55349><56499>-<55349><56500>]
(每個代理對都會被其程式碼取代)。現在很容易看出範圍 56499-55349
無效:它的起始程式碼 56499
大於結束程式碼 55349
。這是發生錯誤的正式原因
使用旗標 u
,模式會正確運作
// look for characters from 𝒳 to 𝒵
alert( '𝒴'.match(/[𝒳-𝒵]/u) ); // 𝒴
留言
<code>
標籤,對於多行程式碼 - 請使用<pre>
標籤,對於超過 10 行的程式碼 - 請使用沙盒 (plnkr、jsbin、codepen…)