C++11/14介紹(六)——正則表達式庫(二)

std::regex及其相關

對字符串內容進行匹配的最常見手段就是使用正則表達式。可惜在傳統 C++ 中正則表達式一直沒有得到語言層面的支持,沒有納入標準庫,而 C++ 作爲一門高性能語言,在後臺服務的開發中,對 URL 資源鏈接進行判斷時,使用正則表達式也是工業界最爲成熟的普遍做法。

一般的解決方案就是使用 boost 的正則表達式庫。而 C++11 正式將正則表達式的的處理方法納入標準庫的行列,從語言級上提供了標準的支持,不再依賴第三方。

C++11 提供的正則表達式庫操作 std::string 對象,模式 std::regex (本質是 std::basic_regex)進行初始化,通過 std::regex_match 進行匹配,從而產生 std::smatch (本質是 std::match_results對象)。

考慮下面的正則表達式

  • [a-z]+\.txt: 在這個正則表達式中, [a-z] 表示匹配一個小寫字母, + 可以使前面的表達式匹配多次,因此 [a-z]+ 能夠匹配一個小寫字母組成的字符串。在正則表達式中一個 . 表示匹配任意字符,而 . 則表示匹配字符 .,最後的 txt 表示嚴格匹配 txt 則三個字母。因此這個正則表達式的所要匹配的內容就是由純小寫字母組成的文本文件。

std::regex_match 用於匹配字符串和正則表達式,有很多不同的重載形式。最簡單的一個形式就是傳入std::string 以及一個 std::regex 進行匹配,當匹配成功時,會返回 true,否則返回 false。例如:

#include <iostream>
#include <string>
#include <regex>

int main() {
    std::string fnames[] = {"foo.txt", "bar.txt", "test", "a0.txt", "AAA.txt"};
    // 在 C++ 中 `\` 會被作爲字符串內的轉義符,爲使 `\.` 作爲正則表達式傳遞進去生效,需要對 `\` 進行二次轉義,從而有 `\\.`
    std::regex txt_regex("[a-z]+\\.txt");
    for (const auto &fname: fnames)
        std::cout << fname << ": " << std::regex_match(fname, txt_regex) << std::endl;
}

另一種常用的形式就是依次傳入 std::string/std::smatch/std::regex 三個參數,其中 std::smatch 的本質其實是 std::match_results,在標準庫中, std::smatch 被定義爲了 std::match_results<std::string::const_iterator>,也就是一個子串迭代器類型的 match_results。使用 std::smatch可以方便的對匹配的結果進行獲取,例如:

std::regex base_regex("([a-z]+)\\.txt");
std::smatch base_match;
for(const auto &fname: fnames) {
    if (std::regex_match(fname, base_match, base_regex)) {
        // sub_match 的第一個元素匹配整個字符串
        // sub_match 的第二個元素匹配了第一個括號表達式
        if (base_match.size() == 2) {
            std::string base = base_match[1].str();
            std::cout << "sub-match[0]: " << base_match[0].str() << std::endl;
            std::cout << fname << " sub-match[1]: " << base << std::endl;
        }
    }
}

結果:

foo.txt: 1
bar.txt: 1
test: 0
a0.txt: 0
AAA.txt: 0
sub-match[0]: foo.txt
foo.txt sub-match[1]: foo
sub-match[0]: bar.txt
bar.txt sub-match[1]: bar
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章