快速入門
教學
工具和語言
範例
參考
書籍評論
正規表示式工具
grep
PowerGREP
RegexBuddy
RegexMagic
一般應用程式
EditPad Lite
EditPad Pro
語言和函式庫
Boost
Delphi
GNU (Linux)
Groovy
Java
JavaScript
.NET
PCRE (C/C++)
PCRE2 (C/C++)
Perl
PHP
POSIX
PowerShell
Python
R
Ruby
std::regex
Tcl
VBScript
Visual Basic 6
wxWidgets
XML Schema
Xojo
XQuery 和 XPath
XRegExp
資料庫
MySQL
Oracle
PostgreSQL
此網站上的更多資訊
簡介
正規表示式快速入門
正規表示式教學
取代字串教學
應用程式和語言
正規表示式範例
正規表示式參考
取代字串參考
書籍評論
可列印 PDF
關於此網站
RSS Feed 和部落格
RegexBuddy—The best regex editor and tester for C++ developers!

使用 std::regex 的 C++ 正規表示式

C++11 標準中定義的 C++ 標準函式庫在 <regex> 標頭中提供正規表示式的支援。在 C++11 之前,<regex> 是 C++ 標準函式庫的 TR1 延伸模組的一部分。當此網站提到 std::regex 時,是指包含在 Visual C++ 2008 及更新版本中的 C++ 標準函式庫的 Dinkumware 實作。當目標為 Win64 時,C++Builder XE3 及更新版本也支援此函式庫。在 Visual C++ 2008 中,命名空間是 std::tr1::regex,而不是 std::regex。

C++Builder 10 及更新版本支援 Dinkumware 實作 std::regex,只要將使用傳統 Borland 編譯器的選項停用,即可鎖定 Win32。在 C++Builder XE3 及更新版本中使用傳統 Borland 編譯器時,您可以使用 boost::regex 取代 std::regex。雖然 std::regex 在 TR1 和 C++11 中定義的運算和類別與 boost::regex 幾乎相同,但實際 regex 風格仍有許多重要的差異。最重要的是,Boost 中的 ECMAScript regex 語法新增了許多從 Perl 借用的功能,這些功能並非 ECMAScript 標準的一部分,且未在 Dinkumware 函式庫中實作。

六種正規表示法風格

std::regex_constants 中定義了六種不同的正規表示法風格或語法

大多數 C++ 參考都說明 C++11 實作了 ECMA-262v3 和 POSIX 標準中定義的正規表示法。但實際上,C++ 實作是根據這些標準非常鬆散地建立的。語法非常接近。唯一的重大差異是 std::regex 即使在 ECMAScript 模式下也支援 POSIX 類別,且對於哪些字元必須跳脫(例如大括號和右中括號)以及哪些字元不需跳脫(例如字母)有些特別。

但此語法的實際行為有重要的差異。在 std::regex 中,插入符號和美元符號 始終會與內嵌換行符號相符,而在 JavaScript 和 POSIX 中,這是一個選項。與大多數 regex 風格一樣,對非參與群組的反向參照無法相符,而在 JavaScript 中,它們會找到零長度相符。在 JavaScript 中,\d\w 僅限於 ASCII,而 \s 則相符於所有 Unicode 空白。這很奇怪,但所有現代瀏覽器都遵循此規範。在 std::regex 中,使用 char 字串時,所有 簡寫 都僅限於 ASCII。在 Visual C++ 中(但 C++Builder 中沒有),使用 wchar_t 字串時,它們支援 Unicode。在 Visual C++ 中使用 wchar_t 時,POSIX 類別 也會相符於非 ASCII 字元,但並未一致包含所有預期的 Unicode 字元。

實際上,您大多會使用 ECMAScript 語法。它是預設語法,提供的功能遠多於其他語法。每當本網站上的教學課程提到 std::regex 但未提到任何語法時,所寫的內容就適用於 ECMAScript 語法,可能適用於其他語法,也可能不適用。您實際上只會在想要重複使用舊 POSIX 程式碼或 UNIX 指令碼中的現有正規表示法時,才會使用其他語法。

建立正規表示式物件

在使用正規表示式之前,您必須建立範本類別 std::basic_regex 的物件。如果您要處理的主題是 char 陣列或 std::string 物件,您可以輕鬆地使用這個範本類別的 std::regex 實例化來執行此動作。如果您要處理的主題是 wchar_t 陣列或 std::wstring 物件,請使用 std::wregex 實例化。

將您的正規表示式作為字串傳遞給建構函式的第一個參數。如果您想要使用 ECMAScript 以外的正規表示式風格,請將適當的常數作為第二個參數傳遞。您可以將這個常數「或」運算 std::regex_constants::icase,以讓正規表示式不區分大小寫。您也可以將它「或」運算 std::regex_constants::nosubs,以將所有擷取群組轉換為非擷取群組,如果您只關心整體正規表示式比對,而且不想要擷取任何擷取群組比對到的文字,這樣可以讓您的正規表示式更有效率。

尋找正規表示式比對

呼叫 std::regex_search(),並將您的主題字串作為第一個參數,將正規表示式物件作為第二個參數,以檢查您的正規表示式是否可以比對字串的任何部分。如果您想要檢查您的正規表示式是否可以比對整個主題字串,請呼叫 std::regex_match(),並使用相同的參數。由於 std::regex 缺乏專門在字串開頭和結尾比對的錨定,因此您在使用正規表示式驗證使用者輸入時,必須呼叫 regex_match()。

regex_search() 和 regex_match() 都只會傳回 true 或 false。若要取得 regex_search() 比對到的字串部分,或是在使用任一函式時取得擷取群組比對到的字串部分,您需要將範本類別 std::match_results 的物件作為第二個參數傳遞。正規表示式物件接著會成為第三個參數。使用下列四個範本實例化之一的預設建構函式來建立這個物件

當函式呼叫傳回 true 時,您可以呼叫 match_results 物件的 str()、position() 和 length() 成員函式,以取得配對的文字,或相對於主旨字串的配對開始位置及其長度。呼叫這些成員函式時不帶參數或以 0 為參數,以取得整體 regex 配對。呼叫時傳遞 1 或更大的數字,以取得特定擷取群組的配對。size() 成員函式指出擷取群組的數量,加上整體配對的 1。因此,您可以傳遞一個值,範圍為 size()-1,至其他三個成員函式。

將所有內容組合在一起,我們可以像這樣取得第一個擷取群組配對的文字

std::string subject("Name: John Doe");
std::string result;
try {
  std::regex re("Name: (.*)");
  std::smatch match;
  if (std::regex_search(subject, match, re) && match.size() > 1) {
    result = match.str(1);
  } else {
    result = std::string("");
  }
} catch (std::regex_error& e) {
  // Syntax error in the regular expression
}

尋找所有 Regex 配對

若要尋找字串中的所有 regex 配對,您需要使用反覆運算器。使用這四個範本實例化之一,建立範本類別 std::regex_iterator 的物件

呼叫建構函式並使用三個參數來建立一個物件:指出搜尋開始位置的字串反覆運算器、指出搜尋結束位置的字串反覆運算器,以及 regex 物件。如果找到任何配對,物件在建立時將包含第一個配對。使用預設建構函式建立另一個反覆運算器物件,以取得序列結束反覆運算器。您可以將第一個物件與第二個物件進行比較,以判斷是否有任何進一步的配對。只要第一個物件不等於第二個物件,您就可以取消第一個物件的參考,以取得 match_results 物件。

std::string subject("This is a test");
try {
  std::regex re("\\w+");
  std::sregex_iterator next(subject.begin(), subject.end(), re);
  std::sregex_iterator end;
  while (next != end) {
    std::smatch match = *next;
    std::cout << match.str() << "\n";
    next++;
  }
} catch (std::regex_error& e) {
  // Syntax error in the regular expression
}

取代所有配對

若要取代字串中的所有配對,請呼叫 std::regex_replace(),並將您的主旨字串作為第一個參數、regex 物件作為第二個參數,以及包含取代文字的字串作為第三個參數。此函式會傳回一個套用取代結果的新字串。

替換字串的語法與 JavaScript 類似,但並非完全相同。無論您使用哪種 regex 語法或文法,都會使用相同的替換字串語法。您可以使用 $&$0 來插入整個 regex 比對,並使用 $1$9 來插入前九個擷取群組比對到的文字。沒有辦法插入第 10 個或更高群組比對到的文字。$10 和更高群組永遠會被替換為空白,而 $9 和更低群組如果 regex 中的擷取群組少於要求的數字,也會被替換為空白。$`(美元符號反引號)是比對左側的字串部分,而 $'(美元符號單引號)是比對右側的字串部分。

| 快速入門 | 教學 | 工具和語言 | 範例 | 參考 | 書籍評論 |

| grep | PowerGREP | RegexBuddy | RegexMagic |

| EditPad Lite | EditPad Pro |

| Boost | Delphi | GNU (Linux) | Groovy | Java | JavaScript | .NET | PCRE (C/C++) | PCRE2 (C/C++) | Perl | PHP | POSIX | PowerShell | Python | R | Ruby | std::regex | Tcl | VBScript | Visual Basic 6 | wxWidgets | XML Schema | Xojo | XQuery 和 XPath | XRegExp |

| MySQL | Oracle | PostgreSQL |