快速開始
教學
工具和語言
範例
參考
書籍評論
正規表示式教學
簡介
目錄
特殊字元
不可列印字元
正規表示式引擎內部
字元類別
字元類別減法
字元類別交集
簡寫字元類別
點號
錨點
字詞邊界
交替
選用項目
重複
群組和擷取
反向參照
反向參照,第 2 部分
命名群組
相對反向參照
分支重設群組
自由間距和註解
Unicode
模式修改器
原子群組
獨佔量詞
前瞻和後顧
環顧,第 2 部分
將文字排除在符合項之外
條件式
平衡群組
遞迴
子常式
無限遞迴
遞迴和量詞
遞迴和擷取
遞迴和反向參照
遞迴和回溯
POSIX 方括號表示式
零長度符合項
持續符合項
本網站的其他資訊
簡介
正規表示式快速開始
正規表示式教學
取代字串教學
應用程式和語言
正規表示式範例
正規表示式參考
取代字串參考
書籍評論
可列印 PDF
關於本網站
RSS 饋送和部落格
RegexBuddy—Better than a regular expression tutorial!

點號符合(幾乎)任何字元

在正規表示式中,點號或句點是最常使用的後設字元之一。不幸的是,它也是最常被誤用的後設字元。

點號符合單一字元,不論該字元為何。唯一的例外是換行字元。在本教學中討論的所有正規表示式風味,點號預設不會符合換行字元。

這個例外主要是由於歷史原因。第一批使用正規表示式的工具是基於行的。它們會逐行讀取檔案,並將正規表示式分別套用至每一行。這些工具的效果是,字串永遠不會包含換行字元,因此點號永遠不會符合它們。

現代工具和語言可將正規表示式套用於非常大的字串,甚至整個檔案。除了 VBScript,本文討論的所有正規表示式版本都有選項,可讓點符號比對所有字元,包括換行符號。較舊的 JavaScript 實作也沒有這個選項。它正式新增於 ECMAScript 2018 規格。

在 PowerGREP 中,勾選標籤為「點符號比對換行符號」的核取方塊,可讓點符號比對所有字元。在 EditPad Pro 中,開啟「點符號」或「點符號比對換行」搜尋選項。

在 Perl 中,點符號也比對換行符號的模式稱為「單行模式」。這有點不幸,因為很容易將這個術語與「多行模式」混淆。多行模式只會影響 錨點,而單行模式只會影響點符號。您可以透過在正規表示式程式碼後方加上 s 來啟用單行模式,如下所示:m/^regex$/s;

其他語言和正規表示式函式庫已採用 Perl 的術語。使用 .NET 的 Regex 類別 時,您可以透過指定 RegexOptions.Singleline 來啟用這個模式,例如 Regex.Match("string", "regex", RegexOptions.Singleline)

JavaScript(為了與舊版瀏覽器相容)和 VBScript 中,您可以使用 字元類別,例如 [\s\S] 來比對任何字元。這個字元比對的字元可能是空白字元(包括換行字元),或是非空白字元。由於所有字元都是空白或非空白,因此這個字元類別會比對任何字元。請勿使用交替,例如 (\s|\S),因為這會 很慢。當然也不要使用 (.|\s),因為這可能會導致 災難性的回溯,因為空白和 tab 可以同時由 .\s 比對。

在所有 Boost 的正規表示式語法中,點符號預設會比對換行符號。Boost 的 ECMAScript 語法允許您使用 regex_constants::no_mod_m 關閉此功能。

換行符號

儘管點在各種正規表示法中都受到支援,但它們視為換行字元的字元卻有顯著差異。所有正規表示法都將換行符號 \n 視為換行字元。UNIX 文字檔以單一換行符號作為結尾。本教學課程中討論的所有指令碼語言都不會將其他字元視為換行字元。即使在 Windows 上,文字檔通常會以 \r\n 字元對作為結尾,這也不會造成問題。這是因為這些指令碼語言預設會以文字模式讀取和寫入檔案。在 Windows 上執行時,\r\n 字元對會在讀取檔案時自動轉換為 \n,而 \n 會自動寫入檔案為 \r\n

std::regexXML SchemaXPath 也將回車符號 \r 視為換行字元。除了這些之外,JavaScript 還加入了 Unicode 換行分隔符號 \u2028 和段落分隔符號 \u2029Java 則包含這些字元,以及 Latin-1 下一列控制字元 \u0085Boost 則在清單中加入換頁符號 \f。只有 DelphiJGsoft 正規表示法 支援所有 Unicode 換行字元,並以垂直定位標籤完成組合。

.NET 特別沒有出現在視 \n 以外的字元為換行字元的正規表示法清單中。與根植於 UNIX 世界的指令碼語言不同,.NET 是 Windows 開發架構,不會自動從它讀取的文字檔中移除回車字元。如果您將 Windows 文字檔整體讀取為字串,它將包含回車字元。如果您對該字串使用正規表示法 abc.*,而沒有設定 RegexOptions.SingleLine,它將比對 abc 加上同一行中後面的所有字元,以及行尾的回車字元,但沒有後面的換行字元。

有些正規表示法允許您控制哪些字元應視為換行字元。Java 有 UNIX_LINES 選項,讓它只將 \n 視為換行字元。PCRE 有選項讓您可以在僅 \n、僅 \r\r\n 或所有 Unicode 換行字元之間進行選擇。

POSIX 系統上,POSIX 區域設定會決定哪些字元是換行字元。C 區域設定只將換行符號 \n 視為換行字元。Unicode 區域設定支援所有 Unicode 換行字元。

\N 永不比對換行字元

Perl 5.12 和 PCRE 8.10 導入了 \N,它會比對任何單一非換行字元,就像句點一樣。不同於句點,\N 不受「單行模式」影響。(?s)\N. 會開啟單行模式,然後比對任何非換行字元,後接任何字元,無論它是否為換行字元。

PCRE 的選項會控制哪些字元被視為換行字元,它們會以完全相同的方式影響 \N,就像它們影響句點一樣。

PHP 5.3.4 和 R 2.14.0 也支援 \N,因為它們的正規表示法支援是基於 PCRE 8.10 或更新版本。JGsoft V2 也支援 \N

謹慎使用句點

句點是一個非常強大的正規表示法元字元。它允許你偷懶。放一個句點,當你在有效資料上測試正規表示法時,所有東西都會完美比對。問題是,正規表示法也會在不應該比對的情況下比對。如果你對正規表示法很陌生,有些情況一開始可能不太明顯。

讓我們用一個簡單的範例來說明這一點。假設我們想要比對 mm/dd/yy 格式的日期,但我們想要讓使用者選擇日期分隔符號。快速的方法是 \d\d.\d\d.\d\d。一開始看起來很好。它可以完美比對 02/12/03 這樣的日期。問題是:02512703 也被這個正規表示法視為有效的日期。在此比對中,第一個句點比對 5,第二個比對 7。顯然不是我們想要的。

\d\d[- /.]\d\d[- /.]\d\d 是更好的方法。這個正規表示法允許使用連字號、空格、句點和正斜線作為日期分隔符號。請記住,句點在 字元類別 中不是元字元,所以我們不需要用反斜線來跳脫它。

此正規表示法仍遠未完美。它將 99/99/99 匹配為有效日期。 [01]\d[- /.][0-3]\d[- /.]\d\d 雖更進一步,但仍會匹配 19/39/99。您希望正規表示法有多麼完美,取決於您想用它做什麼。如果您要驗證使用者輸入,則必須完美。如果您要從每次以相同方式產生檔案的已知來源解析資料檔案,我們的最後嘗試可能已足夠解析資料而不會出錯。您可以在範例區段中找到 更佳的正規表示法來匹配日期

使用否定字元類別,而非點號

否定字元類別 通常比點號更合適。說明重複運算子 星號和加號 的教學區段更詳細地介紹了這一點。但此警告很重要,因此在此也提到。讓我們再次以範例說明。

假設您想要匹配雙引號字串。聽起來很容易。我們可以在雙引號之間放置任何數量的任何字元,因此 ".*" 似乎就能順利完成任務。點號匹配任何字元,而星號允許點號重複任何次數,包括零次。如果您針對 在雙引號之間放置一個「字串」 測試此正規表示法,它會完美地匹配 "字串"。現在繼續針對 休士頓,我們對「字串一」和「字串二」有問題。請回應。 進行測試。

糟糕。正規表示法匹配 "字串一" 和 "字串二"。絕對不是我們預期的結果。原因在於 星號貪婪的

在日期比對範例中,我們透過將點替換為字元類別來改善我們的正規表示式。在此,我們對否定字元類別執行相同的動作。我們對雙引號字串的原始定義有瑕疵。我們不想要任何數量的任何字元出現在引號之間。我們想要任何數量不在引號之間的雙引號或換行字元。因此,適當的正規表示式為 "[^"\r\n]*"。如果您的版本支援 簡寫 \v 來比對任何換行字元,則 "[^"\v]*" 是更好的解決方案。