2022 年 8 月 7 日

交替 (OR) |

正規表示法中交替這個術語實際上是一個簡單的「OR」。

在正規表示法中,它以垂直線字元 | 表示。

例如,我們需要尋找程式語言:HTML、PHP、Java 或 JavaScript。

對應的正規表示法:html|php|java(script)?

使用範例

let regexp = /html|php|css|java(script)?/gi;

let str = "First HTML appeared, then CSS, then JavaScript";

alert( str.match(regexp) ); // 'HTML', 'CSS', 'JavaScript'

我們已經看過類似的東西 - 方括號。它們允許在多個字元之間進行選擇,例如 gr[ae]y 符合 graygrey

方括號只允許字元或字元類別。交替允許任何表示法。正規表示法 A|B|C 表示表示法 ABC 之一。

例如

  • gr(a|e)y 的意思與 gr[ae]y 完全相同。
  • gra|ey 表示 graey

若要將交替套用至樣式的特定部分,我們可以將其括在括號中

  • I love HTML|CSS 符合 I love HTMLCSS
  • I love (HTML|CSS) 符合 I love HTMLI love CSS

範例:時間正規表示法

在先前的文章中,有一個任務是要建立一個正規表示法,用於搜尋時間格式為 hh:mm,例如 12:00。但是,單純的 \d\d:\d\d 太過模糊。它會將 25:99 視為時間(因為 99 分鐘符合樣式,但該時間無效)。

我們如何建立一個更好的樣式?

我們可以使用更仔細的比對。首先,時

  • 如果第一個數字是 01,則下一個數字可以是任何數字:[01]\d
  • 否則,如果第一個數字是 2,則下一個數字必須是 [0-3]
  • (不允許其他第一個數字)

我們可以使用交替在正規表示法中寫入兩個變數:[01]\d|2[0-3]

接下來,分鐘必須介於 0059。在正規表示法語言中,這可以寫成 [0-5]\d:第一個數字為 0-5,然後是任何數字。

如果我們將時和分黏貼在一起,我們會得到樣式:[01]\d|2[0-3]:[0-5]\d

我們幾乎完成了,但有一個問題。交替 | 現在發生在 [01]\d2[0-3]:[0-5]\d 之間。

也就是說:分鐘會新增到第二個交替變數,以下是一個清楚的範例

[01]\d  |  2[0-3]:[0-5]\d

該樣式尋找 [01]\d2[0-3]:[0-5]\d

但這是不對的,交替應該只用於正規表示法的「時」部分,以允許 [01]\d2[0-3]。讓我們透過將「時」括在括號中來修正它:([01]\d|2[0-3]):[0-5]\d

最終解決方案

let regexp = /([01]\d|2[0-3]):[0-5]\d/g;

alert("00:00 10:10 23:59 25:99 1:2".match(regexp)); // 00:00,10:10,23:59

任務

有許多程式語言,例如 Java、JavaScript、PHP、C、C++。

建立一個正規表示法,在字串 Java JavaScript PHP C++ C 中找到它們

let regexp = /your regexp/g;

alert("Java JavaScript PHP C++ C".match(regexp)); // Java JavaScript PHP C++ C

第一個想法可能是使用 | 在語言之間列出。

但這並不正確

let regexp = /Java|JavaScript|PHP|C|C\+\+/g;

let str = "Java, JavaScript, PHP, C, C++";

alert( str.match(regexp) ); // Java,Java,PHP,C,C

正規表示式引擎會逐一尋找交替項。也就是說:它會先檢查我們是否有 Java,否則會尋找 JavaScript,依此類推。

因此,永遠找不到 JavaScript,只因為 Java 會先被檢查。

CC++ 相同。

這個問題有兩個解決方案

  1. 變更順序,先檢查較長的比對:JavaScript|Java|C\+\+|C|PHP
  2. 合併開頭相同的變體:Java(Script)?|C(\+\+)?|PHP

實際操作

let regexp = /Java(Script)?|C(\+\+)?|PHP/g;

let str = "Java, JavaScript, PHP, C, C++";

alert( str.match(regexp) ); // Java,JavaScript,PHP,C,C++

「bb-tag」看起來像 [tag]...[/tag],其中 tag 為下列之一:burlquote

例如

[b]text[/b]
[url]http://google.com[/url]

BB-tag 可以巢狀。但標籤無法巢狀到它自己,例如

Normal:
[url] [b]http://google.com[/b] [/url]
[quote] [b]text[/b] [/quote]

Can't happen:
[b][b]text[/b][/b]

標籤可以包含換行符號,這是正常的

[quote]
  [b]text[/b]
[/quote]

建立一個正規表示式來尋找所有包含其內容的 BB-tag。

例如

let regexp = /your regexp/flags;

let str = "..[url]http://google.com[/url]..";
alert( str.match(regexp) ); // [url]http://google.com[/url]

如果標籤是巢狀的,則我們需要外層標籤(如果我們願意,可以在其內容中繼續搜尋)

let regexp = /your regexp/flags;

let str = "..[url][b]http://google.com[/b][/url]..";
alert( str.match(regexp) ); // [url][b]http://google.com[/b][/url]

開啟標籤為 \[(b|url|quote)]

然後要尋找直到關閉標籤的所有內容,讓我們使用模式 .*?,並加上旗標 s,以比對任何字元,包括換行符號,然後新增一個反向參照到關閉標籤。

完整的模式:\[(b|url|quote)\].*?\[/\1]

實際操作

let regexp = /\[(b|url|quote)].*?\[\/\1]/gs;

let str = `
  [b]hello![/b]
  [quote]
    [url]http://google.com[/url]
  [/quote]
`;

alert( str.match(regexp) ); // [b]hello![/b],[quote][url]http://google.com[/url][/quote]

請注意,除了跳脫 [ 之外,我們還必須為關閉標籤 [\/\1] 跳脫斜線,因為斜線通常會關閉模式。

建立一個正規表示式來尋找雙引號中的字串 "..."

這些字串應支援跳脫,就像 JavaScript 字串一樣。例如,引號可以插入為 \",換行符號為 \n,而反斜線本身為 \\

let str = "Just like \"here\".";

請特別注意,跳脫的引號 \" 不會結束字串。

因此,我們應該從一個引號搜尋到另一個引號,並忽略途中跳脫的引號。

這是任務的精髓,否則將會很簡單。

要比對的字串範例

.. "test me" ..
.. "Say \"Hello\"!" ... (escaped quotes inside)
.. "\\" ..  (double backslash inside)
.. "\\ \"" ..  (double backslash and an escaped quote inside)

在 JavaScript 中,我們需要加倍反斜線才能將它們傳遞到字串中,如下所示

let str = ' .. "test me" .. "Say \\"Hello\\"!" .. "\\\\ \\"" .. ';

// the in-memory string
alert(str); //  .. "test me" .. "Say \"Hello\"!" .. "\\ \"" ..

解決方案:/"(\\.|[^"\\])*"/g

逐步說明

  • 首先,我們尋找開啟引號 "
  • 然後,如果我們有一個反斜線 \\(我們必須在模式中加倍,因為它是一個特殊字元),則在反斜線之後任何字元都很好(一個點)。
  • 否則,我們會採用任何字元,除了引號(表示字串的結尾)和反斜線(為了防止孤立的反斜線,反斜線僅用於其後的其他符號):[^"\\]
  • …以此類推,直到結束引號。

實際操作

let regexp = /"(\\.|[^"\\])*"/g;
let str = ' .. "test me" .. "Say \\"Hello\\"!" .. "\\\\ \\"" .. ';

alert( str.match(regexp) ); // "test me","Say \"Hello\"!","\\ \""

撰寫一個正規表示法來尋找標籤<style...>。它應該符合完整的標籤:它可能沒有屬性<style>或有幾個屬性<style type="..." id="...">

…但正規表示法不應符合<styler>

例如

let regexp = /your regexp/g;

alert( '<style> <styler> <style test="...">'.match(regexp) ); // <style>, <style test="...">

模式開頭很明顯:<style

…但接著我們不能簡單地寫入<style.*?>,因為<styler>會符合它。

我們需要在<style之後加上一個空格,然後選擇性地加上其他內容或結尾>

在正規表示法語言中:<style(>|\s.*?>)

實際操作

let regexp = /<style(>|\s.*?>)/g;

alert( '<style> <styler> <style test="...">'.match(regexp) ); // <style>, <style test="...">
教學課程地圖

留言

留言前請先閱讀此內容…
  • 如果您有改善建議,請提交 GitHub 問題或提交拉取請求,而不是留言。
  • 如果您無法理解文章中的某些內容,請加以說明。
  • 若要插入幾個字元的程式碼,請使用<code>標籤,對於多行,請將它們包覆在<pre>標籤中,對於超過 10 行的內容,請使用沙盒 (plnkrjsbincodepen…)