2020 年 12 月 7 日

模式和旗標

正規表示式是一種模式,提供強大的方式來搜尋和取代文字。

在 JavaScript 中,它們可透過 RegExp 物件取得,並整合在字串的方法中。

正規表示式

正規表示式(也稱為「regexp」或「reg」)包含一個模式和選用的旗標

有兩種語法可建立正規表示式物件。

「長」語法

regexp = new RegExp("pattern", "flags");

以及「短」語法,使用斜線 "/"

regexp = /pattern/; // no flags
regexp = /pattern/gmi; // with flags g,m and i (to be covered soon)

斜線 /.../ 告訴 JavaScript 我們正在建立正規表示式。它們扮演與字串引號相同的角色。

在兩種情況下,regexp 都會成為內建 RegExp 類別的執行個體。

這兩種語法之間的主要差異在於,使用斜線 /.../ 的模式不允許插入運算式(例如包含 ${...} 的字串範本字面值)。它們是完全靜態的。

當我們在編寫程式碼時知道正規表示式時,就會使用斜線分隔符號,而這也是最常見的情況。而當我們需要從動態產生的字串中「即時」建立正規表示式時,則較常使用 new RegExp。例如

let tag = prompt("What tag do you want to find?", "h2");

let regexp = new RegExp(`<${tag}>`); // same as /<h2>/ if answered "h2" in the prompt above

旗標

正規表示式可能有影響搜尋的旗標。

JavaScript 中只有 6 個旗標

i
使用此旗標,搜尋會區分大小寫:Aa 沒有差別(請參閱以下範例)。
g
使用此旗標,搜尋會尋找所有符合的項目,而沒有此旗標,只會傳回第一個符合的項目。
m
多行模式(在章節 錨點 ^ $ 的多行模式,旗標「m」 中介紹)。
s
啟用「點全部」模式,允許點 . 符合換行字元 \n(在章節 字元類別 中介紹)。
u
啟用完整的 Unicode 支援。此旗標會啟用代理對的正確處理。在章節 Unicode:旗標「u」和類別 \p{...} 中有更詳細的說明。
y
「黏著」模式:在文字中的確切位置進行搜尋(在章節 黏著旗標「y」,在位置進行搜尋 中介紹)
顏色

從這裡開始,色彩配置如下

  • 正規表示式 – 紅色
  • 字串(我們搜尋的範圍)– 藍色
  • 結果 – 綠色

搜尋:str.match

如前所述,正規表示式已整合到字串方法中。

方法 str.match(regexp) 會在字串 str 中找出所有符合 regexp 的項目。

它有 3 種工作模式

  1. 如果正規表示式有旗標 g,它會傳回一個陣列,其中包含所有符合的項目

    let str = "We will, we will rock you";
    
    alert( str.match(/we/gi) ); // We,we (an array of 2 substrings that match)

    請注意,Wewe 都會被找到,因為旗標 i 使正規表示式不區分大小寫。

  2. 如果沒有此旗標,它只會傳回第一個符合的項目,形式為陣列,其中完整符合的項目在索引 0 中,而其他詳細資料則在屬性中

    let str = "We will, we will rock you";
    
    let result = str.match(/we/i); // without flag g
    
    alert( result[0] );     // We (1st match)
    alert( result.length ); // 1
    
    // Details:
    alert( result.index );  // 0 (position of the match)
    alert( result.input );  // We will, we will rock you (source string)

    如果正規表示式的一部分包含在括弧中,陣列可能會包含 0 以外的其他索引。我們將在章節 擷取群組 中介紹這個部分。

  3. 最後,如果沒有符合的項目,就會傳回 null(不論是否有旗標 g)。

    這是一個非常重要的細微差別。如果沒有匹配項,我們不會收到一個空陣列,而是收到 null。忘記這一點可能會導致錯誤,例如

    let matches = "JavaScript".match(/HTML/); // = null
    
    if (!matches.length) { // Error: Cannot read property 'length' of null
      alert("Error in the line above");
    }

    如果我們希望結果始終是一個陣列,我們可以這樣寫

    let matches = "JavaScript".match(/HTML/) || [];
    
    if (!matches.length) {
      alert("No matches"); // now it works
    }

替換:str.replace

方法 str.replace(regexp, replacement) 使用 replacement 替換字串 str 中使用 regexp 找到的匹配項(如果存在標記 g,則替換所有匹配項;否則,只替換第一個匹配項)。

例如

// no flag g
alert( "We will, we will".replace(/we/i, "I") ); // I will, we will

// with flag g
alert( "We will, we will".replace(/we/ig, "I") ); // I will, I will

第二個參數是 replacement 字串。我們可以在其中使用特殊字元組合來插入匹配項的片段

符號 替換字串中的動作
$& 插入整個匹配項
$` 插入匹配項之前的字串部分
$' 插入匹配項之後的字串部分
$n 如果 n 是 1-2 位數字,則插入第 n 個括號的內容,有關更多資訊,請參閱章節 擷取群組
$<name> 插入具有給定 name 的括號的內容,有關更多資訊,請參閱章節 擷取群組
$$ 插入字元 $

使用 $& 的範例

alert( "I love HTML".replace(/HTML/, "$& and JavaScript") ); // I love HTML and JavaScript

測試:regexp.test

方法 regexp.test(str) 尋找至少一個匹配項,如果找到,則傳回 true,否則傳回 false

let str = "I love JavaScript";
let regexp = /LOVE/i;

alert( regexp.test(str) ); // true

在本章節稍後,我們將研究更多正規表示法,逐步示範更多範例,並認識其他方法。

有關這些方法的完整資訊,請參閱文章 RegExp 和字串的方法

摘要

  • 正規表示法包含一個模式和一些選用標記: gimusy
  • 沒有標記和特殊符號(我們稍後會研究),使用正規表示法的搜尋與子字串搜尋相同。
  • 方法 str.match(regexp) 尋找匹配項:如果存在 g 標記,則尋找所有匹配項;否則,只尋找第一個匹配項。
  • 方法 str.replace(regexp, replacement) 使用 replacement 替換使用 regexp 找到的匹配項:如果存在 g 標記,則替換所有匹配項;否則,只替換第一個匹配項。
  • 方法 regexp.test(str) 如果至少有一個匹配項,則傳回 true;否則,傳回 false
教學課程地圖

留言

留言前請先閱讀…
  • 如果您有建議要如何改進 - 請 提交 GitHub 議題 或提交 Pull Request,而不是留言。
  • 如果您無法理解文章中的某些內容 - 請詳細說明。
  • 若要插入幾行程式碼,請使用 <code> 標籤,若要插入多行,請將它們包裝在 <pre> 標籤中,若要插入超過 10 行,請使用沙盒 (plnkrjsbincodepen…)