Javascript 集合和范圍 [...]

2023-02-17 11:01 更新

在方括號 ?[…]? 中的幾個字符或者字符類表示“搜索給定字符中的任意一個”。

集合

例如,[eao] 表示以下 3 個字符中的任何一個:'a'、'e' 或 'o' 。

這就是所謂的 集合。在正則表達式中,可以將集合和常規(guī)字符一起使用。

// 查找 [t 或 m],然后匹配 "op"
alert( "Mop top".match(/[tm]op/gi) ); // "Mop", "top"

請注意,雖然集合中有多個字符,但它們在匹配中只會對應(yīng)其中的一個。

所以在下面的示例中并沒有匹配項:

// 查找 "V",然后匹配 [o 或 i],之后匹配 "la"
alert( "Voila".match(/V[oi]la/) ); // null,無匹配項

這個模式會搜索:

  • ?V?,
  • 然后匹配其中的 一個字符 ?[oi]?,
  • 然后匹配 ?la?。

所以可以匹配上 Vola 或者 Vila

范圍

方括號也可以包含 字符范圍。

例如,[a-z] 表示從 a 到 z 范圍內(nèi)的字符,[0-5] 表示從 0 到 5 的數(shù)字。

在下面的示例中,我們將搜索首先是 "x",然后有兩位數(shù)或兩個在 A 到 F 范圍內(nèi)的字符緊隨其后的字符串。

alert( "Exception 0xAF".match(/x[0-9A-F][0-9A-F]/g) ); // xAF

[0-9A-F] 中有兩個范圍:它搜索一個字符,該字符要么是在 0 到 9 范圍內(nèi)的數(shù)字,要么是從 A 到 F 的字母。

如果我們還想查找小寫字母,則可以添加范圍 a-f[0-9A-Fa-f]?;蛱砑訕?biāo)志 i。

我們也可以在 […] 中使用字符類。

例如,如果我們想查找單詞字符 \w 或連字符 -,則集合可以寫為 [\w-]。

也可以組合多個類,例如 [\s\d] 表示“空格字符或數(shù)字”。

字符類是某些字符集合的簡寫

例如:

  • \d —— 和 [0-9] 相同,
  • \w —— 和 [a-zA-Z0-9_] 相同,
  • \s —— 和 [\t\n\v\f\r ] 外加少量罕見的 Unicode 空格字符相同。

示例:多語言 \w

由于字符類 \w 是簡寫的 [a-zA-Z0-9_],因此無法找到中文象形文字,西里爾字母等。

我們可以編寫一個更通用的模式,該模式可以查找任何語言中的單詞字符。借助 Unicode 屬性很容易實現(xiàn):[\p{Alpha}\p{M}\p{Nd}\p{Pc}\p{Join_C}]。

讓我們理解一下。類似于 \w,我們正在制作一組屬于我們自己的包含具有以下 Unicode 屬性的字符:

  • Alphabetic (Alpha) —— 字母,
  • Mark (M) —— 音調(diào),
  • Decimal_Number (Nd) —— 數(shù)字,
  • Connector_Punctuation (Pc) —— 下劃線 '_' 和類似的字符,
  • Join_Control (Join_C) —— 兩個特殊代碼 200c200d,用于連字,例如阿拉伯語。

使用示例:

let regexp = /[\p{Alpha}\p{M}\p{Nd}\p{Pc}\p{Join_C}]/gu;

let str = `Hi 你好 12`;

// 找出所有字母和數(shù)字:
alert( str.match(regexp) ); // H,i,你,好,1,2

當(dāng)然,我們可以編輯這個模式:添加 Unicode 屬性或刪除它們。Unicode:修飾符 "u" 和類 \p{...} 一文更詳細地介紹了 Unicode 屬性。

IE 瀏覽器不支持 Unicode 屬性

IE 瀏覽器未實現(xiàn) Unicode 屬性 p{...}。如果我們真的需要它們,可以使用庫 XRegExp。

或者只是使用我們感興趣的語言中的字符范圍,例如西里爾字母范圍 [а-я]。

排除范圍

除了普通的范圍匹配,還有像這樣 [^…] 的“排除”范圍匹配。

通過在開頭添加插入符號 ^ 來表示匹配所有 除了給定的字符 之外的任意字符。

例如:

  • [^aeyo] —— 匹配除了 'a''e'、'y''o' 之外的任何字符。
  • [^0-9] —— 匹配除了數(shù)字之外的任何字符,與 \D 作用相同。
  • [^\s] —— 匹配任何非空格字符,與 \S 作用相同。

下面的示例搜索除了字母、數(shù)字和空格之外的任何字符:

alert( "alice15@gmail.com".match(/[^\d\sA-Z]/gi) ); // @ and .

[…] 中的轉(zhuǎn)義

通常當(dāng)我們想要準(zhǔn)確地找到一個特殊字符時,我們需要像 \. 這樣對其進行轉(zhuǎn)義。如果我們需要反斜杠,那么我們需要使用 \\,等等。

在方括號,我們可以使用絕大多數(shù)特殊字符而無需轉(zhuǎn)義:

  • 符號 . + ( ) 無需轉(zhuǎn)義。
  • 在開頭或結(jié)尾(未定義范圍)的連字符 - 不會被轉(zhuǎn)義。
  • 插入符號 ^ 僅在開頭會被轉(zhuǎn)義(表示排除)。
  • 右方括號 ] 總是會被轉(zhuǎn)義(如果我們需要尋找那個符號)。

換句話說,除了在方括號中有特殊含義的字符外,其它所有特殊字符都是允許不轉(zhuǎn)義的。

方括號中的點 . 表示的就是一個點。模式 [.,] 將會搜索字符之一:點或逗號。

在下面的示例中,正則表達式 [-().^+] 查找 -().^+ 中的任何字符:

// 不需要轉(zhuǎn)義
let reg = /[-().^+]/g;

alert( "1 + 2 - 3".match(reg) ); // 匹配 +,-

……但是如果你為了“以防萬一”轉(zhuǎn)義了它們,這也不會有任何問題:

// 轉(zhuǎn)義其中的所有字符
let reg = /[\-\(\)\.\^\+]/g;

alert( "1 + 2 - 3".match(reg) ); // 仍能正常工作:+,-

范圍和修飾符 “u”

如果集合中有代理對(surrogate pairs),則需要標(biāo)志 u 才能使它們正常工作。

例如,讓我們在字符串  中查找 []

alert( ''.match(/[]/) ); // 顯示了一個奇怪的字符,像 [?]
//(搜索執(zhí)行不正確,返回了半個字符)

結(jié)果不正確,因為默認情況下正則表達式“不知道”代理對。

正則表達式引擎認為 [] —— 不是兩個字符,而是四個字符:

  1. 的左半部分 (1)
  2. 的右半部分 (2),
  3. 的左半部分 (3),
  4. 的右半部分 (4)。

我們可以看到它們的編碼,如下所示:

for(let i=0; i<''.length; i++) {
  alert(''.charCodeAt(i)); // 55349, 56499, 55349, 56500
};

因此,上面的示例查找并顯示了  的左半部分。

如果我們添加了修飾符 u,那么行為就正常了:

alert( ''.match(/[]/u) ); // 

當(dāng)我們查找范圍時也會出現(xiàn)類似的情況,就像 [-]

如果我們忘記添加修飾符 u,則會出現(xiàn)錯誤:

''.match(/[-]/); // Error: Invalid regular expression

因為,沒有修飾符 u 時,代理對將被視為兩個字符,所以 [-] 被理解為 [<55349><56499>-<55349><56500>](每個代理對都替換為其代碼)?,F(xiàn)在很容易看出范圍 56499-55349 是無效的:其起始代碼 56499 大于終止代碼 55349。這就是錯誤的原因。

帶有修飾符 u 時,該模式就可以正常匹配了:

// 查找從  到  的字符
alert( ''.match(/[-]/u) ); // 

任務(wù)


Java[^script]

我們有一個正則表達式 /Java[^script]/。

它會和字符串 Java 中的任何一部分匹配嗎?JavaScript 呢?


解決方案

·答案:不會,會

  • 不會。在字符串 Java 中,它不會匹配任何內(nèi)容,因為 [^script] 表示“除了給定的字符之外的任何字符”。因此,這個正則表達式會查找 "Java" 后面是否有匹配這個規(guī)則的字符,但是這已經(jīng)是整個字符串的結(jié)尾了,后面沒有任何字符。

    alert( "Java".match(/Java[^script]/) ); // null
  • 會。因為 [^script] 部分匹配到了字符 "S"。它不是 script。由于正則表達式區(qū)分大小寫(沒有 i 修飾符),因此它將 "S" 視為與 "s" 不同的字符。

    alert( "JavaScript".match(/Java[^script]/) ); // "JavaS"

找到 hh:mm 或者 hh-mm 格式的時間

時間可以通過 hours:minutes 或 hours-minutes 格式來表示。小時和分鐘都有兩位數(shù):09:00 或 21-30。

寫一個正則表達式來找到它們:

let regexp = /your regexp/g;
alert( "Breakfast at 09:00. Dinner at 21-30".match(regexp) ); // 09:00, 21-30

P.S. 在這個任務(wù)中,我們假設(shè)時間總是正確的,不需要過濾像 “45:67” 這樣錯誤的時間字符串。稍后我們也會處理這個問題。


解決方案

答案:\d\d[-:]\d\d。

let regexp = /\d\d[-:]\d\d/g;
alert( "Breakfast at 09:00. Dinner at 21-30".match(regexp) ); // 09:00, 21-30

請注意,破折號 '-' 在方括號中有特殊含義,但只有當(dāng)它位于其它字符之間而不是開頭或結(jié)尾時這個含義才會起作用,所以我們不需要對其進行轉(zhuǎn)義。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號