簡體   English   中英

正則表達式修飾符(或標志)“m”和“s”之間的區別?

[英]Difference between regular expression modifiers (or flags) 'm' and 's'?

我經常忘記正則表達式修飾符ms以及它們的區別。 有什么好方法可以記住它們?

據我了解,他們是:

'm' 用於多行,因此^$將多次匹配字符串的開頭和結尾。 (除以\\n

's' 是這樣的點將匹配甚至換行符

通常,我只是使用

/some_pattern/ism

但最好相應地使用它們(在我的情況下通常是“s”)。

你認為什么是記住它們的好方法,而不是每次都忘記哪個?

找到使用正則表達式多年但仍然不了解這兩個修飾符如何工作的人的情況並不少見。 正如您所觀察到的,名稱“multiline”和“singleline”並不是很有幫助。 它們聽起來必須是相互排斥的,但它們是完全獨立的。 我建議您忽略名稱並專注於它們的作用: m改變錨點( ^$ )的行為,而s改變點( . )的行為。

混淆這些模式的一位著名人物是 Ruby 的作者。 他基於 Perl 創建了自己的正則表達式實現,但他決定讓^$始終作為行錨——也就是說,多行模式始終處於開啟狀態。 不幸的是,他還錯誤地將 dot-matches-everything 模式命名為multiline 所以 Ruby 沒有s修飾符,但它的m修飾符可以做s在其他風格中所做的事情。

至於總是使用/ism ,我建議不要使用它。 正如您所發現的,它基本上是無害的,但它向任何其他試圖弄清楚正則表達式應該做什么的人(甚至是您自己,將來)發送了一個令人困惑的信息。

我喜歡“man perlre”中的解釋:

款待字符串作為ultiple線。
請客字符串為s英格爾線。

對於多行,^ 和 $ 適用於單獨的行(即在換行符之前和之后)。
對於一行,^ 和 $ 適用於整個,而 \\n 只是成為您可以匹配的另一個字符。

[錯誤]按照您的描述同時使用 m 和 s,我希望第二個優先,因此您將始終使用 /ism 處於多行模式。 [/錯誤的]

我讀得不夠遠:
"/s" 和 "/m" 修飾符都覆蓋 $* 設置。 也就是說,無論 $* 包含什么,沒有 "/m" 的 "/s" 將強制 "^" 僅匹配字符串的開頭,而 "$" 僅匹配字符串的結尾(或就在換行符之前)字符串的結尾)。 一起,作為 /ms,他們讓“。” 匹配任何字符,同時仍然允許 "^" 和 "$" 分別匹配字符串中的換行符之后和之前。

2020 年更新:

我可以更清楚地寫出它們是什么,以及一種記住它們的方式,並且我將其寫為與 JavaScript 相關:

  1. 傳統上,JS 正則表達式沒有s標志。 它只有m標志。 到 2020 年 1 月,Firefox 仍然沒有它,而 Chrome 有它。 NodeJS 擁有它。 它在 ES2018 規范中。
  2. s也稱為dotallsingleline 它真的只是為了. 匹配任何(ASCII)字符,包括\\n\\r\
 (換行符)、 \
 (分段\
 )。 當人們問你時,你做什么. 匹配? 如果你回答“任何字符”,那么它並不完全正確。 它是除換行符、 \\r和 unicode 換行符和段落分隔符之外的所有 (ASCII) 字符。 為了真正匹配所有 ASCII 字符,它需要打開s標志。
  3. 為了克服 Firefox 或任何平台中s標志的缺失,它可以是[^][\\s\\S][\\d\\D]等,或(.|\\s)
  4. 就這樣。 這就是傳統 JavaScript 中缺少的s標志。
  5. 現在是m標志。 它代表多行。 它真的很簡單:沒有m標志, ^$將只匹配整個字符串的開頭和結尾。 所以"John Doe\\nMary Lee".match(/^John Doe$/)將不匹配,而"John Doe\\nMary Lee".match(/^John Doe$/m)將匹配。 就這樣。 不要想得太復雜。 它只是改變了^$匹配方式。
  6. 那么“單行”和“多行”是互斥的嗎? 不,他們不是。 例如,如果我想匹配a和任何字符,包括換行符和f ,但a必須在行首, f必須在行尾,即使在 2000 行文本中, "abc \\ndef\\nha".match(/^a.*f$/ms)是需要使用的。 兩者. 匹配\\n ,和^$匹配行首和行尾。

而已。 以上是在 NodeJS 和 Chrome 上測試的,它們已經支持s標志。 (並且長期以來一直支持m標志)。 請記住,您始終可以使用[^]修復s標志缺失問題

現在,為什么過去經常使用msism 因為很多時候,當我們有一個非常長的字符串(例如 2000 行 HTML)時,例如在我們返回的某些 Web 內容的情況下,我們很少希望將^與整個字符串的開頭匹配,並將$與整個字符串的結尾。 所以這就是我們使用m標志的原因。 現在,我們可能想要/<h1>.*?</h1>/匹配,因為(雖然不建議使用正則表達式來匹配 HTML),例如,我們可以使用/<h1>.*?</h1>/進行標題的非貪婪匹配. 我們不介意內容中的\\n ,因為 HTML 的作者可以很好地擁有\\n (或沒有)。 所以這就是我們使用“dotall”標志s

但是如果你試圖從網頁中提取一些信息,你可能不會關心某些東西是在行首還是行尾(因為 HTML 文件中可以有空格(或作為縮進),並且它不會'不會影響頁面內容(通常,除非有<pre>等),因此您不需要使用^$ ,因此您可以忘記m標志。 如果您不介意使用[^]*? 而不是.*? ,那么你也可以忘記s標志——故事結束。

Perl Cookbook 用兩句話說了:

/m/s之間的區別很重要: /m使^$在換行符旁邊匹配,而/s使. 匹配換行符。 您甚至可以一起使用它們 - 它們不是相互排斥的選項。


也許這樣,我永遠不會忘記:

當我想跨行匹配時(通常使用 .*? 來匹配跨多行無關緊要的東西),我自然會想到多行,因此,'m'。 嗯,'m' 實際上不是一個,所以它是 's'。

(因為我已經很好地記住了 'ism'...所以我總能記住它不是 'm',那么它必須是 's')。

其他蹩腳的嘗試包括:

s代表DOTALL,代表DOT匹配ALL。
m是多行——它是為了^$匹配很多次。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM