正規表現にマッチした文字列やその出現位置を調べたい場合には、std::match_results
クラスを活用する必要があります。match_resultsは正規表現用の各種関数の第二引数に指定する形で利用します。
// #include <regex> // using cmatch = std::match_results<const char*>;
std::cmatch results;
if (std::regex_search("Shop99", results, std::regex("\\d+"))) {
std::string s = results.str(); // 99 (マッチした文字列)
auto position = results.position(); // 4 (マッチした文字列の位置)
auto length = results.length(); // 2 (マッチした文字列の長さ)
}
上記のようなC言語スタイルの文字列を検索する場合にはstd::match_results<const char*>
の別名であるstd::cmatch
を用います。std::string
文字列型の場合にはstd::smatch
を用います。
正規表現中の丸括弧()
によってキャプチャされた文字列はサブマッチとして抽出できます。
std::string s = "Shop 99";
std::smatch results;
if (std::regex_match(s, results, std::regex("(\\w+) (\\d+)"))) {
results[0].str(); // "Shop 99" (全体のサブマッチ)
results[1].str(); // "Shop" (`(\\w+)`によるサブマッチ)
results[2].str(); // "99" (`(\\d+)`によるサブマッチ)
}
std::regex_match
関数は正規表現の完全一致を判定する関数です。std::regex_search
は部分一致を判定します。
参考: 正規表現による文字列検索(部分一致/完全一致)【std::regex_search/std::regex_match】
目次
- マッチした全ての文字列を取得する方法(matches, preg_mach_all 相当)
- 文字列別のmatch_results(cmatch, smatch, wcmatch, wsmatch)
- match_resultsで取得できる値や情報、応用方法
マッチした全ての文字列を取得する方法
部分一致した文字列のパターンを全て抽出したい場合には、繰り返し文を用いた部分検索、またはイテレータを用いた探索が必要となります。
イテレータによるパターン抽出(regex_iterator)
std::string
文字列の検索を行う場合にはstd::sregex_iterator
イテレータを用いることができます。
std::vector<std::string> v = {};
std::string s = "Shop 99";
std::regex pt{"\\w+"};
std::sregex_iterator end, ite{s.begin(), s.end(), pt};
for (; ite != end ; ++ite) {
v.push_back(ite->str());
}
// v == {"Shop", "99"}
C言語スタイルの文字列の場合はstd::cregex_iterator
イテレータを用います。
const char* s = "Shop 99";
std::regex pt{"\\w+"};
std::cregex_iterator end, ite{s, s + strlen(s), pt};
for (; ite != end; ++ite) {
v.push_back(ite->str());
}
部分検索によるパターン抽出
文字列がマッチするたびに検索開始位置をずらしていく方法です。
std::vector<std::string> v = {};
std::string s = "Shop 99";
std::smatch m;
auto start = s.cbegin();
while (std::regex_search(start, s.cend(), m, std::regex("\\w+"))) {
v.push_back(m.str());
start = m[0].second;
}
// v == {"Shop", "99"}
m[0].second
はマッチした文字列の次の要素を指すポインタ/イテレータです。
C言語スタイルの文字列の場合は以下の方法を用います。
const char* s = "Shop 99";
std::cmatch m;
const char* start = s;
const char* end = s + std::char_traits<char>::length(s);
while (std::regex_search(start, end, m, std::regex("\\w+"))) {
v.push_back(m.str());
start = m[0].second;
}
文字列別のmatch_results(cmatch, smatch, wcmatch, wsmatch)
C言語スタイルの文字列(const char*
)とC++の文字列(std::string
)でそれぞれ適切なmatch_resultsを用いる必要があります。
文字列 | クラス | 代替表現 |
---|---|---|
const char* | std::cmatch | std::match_results<const char*> |
std::string | std::smatch | std::match_results<string::const_iterator> |
const wchar_t* | std::wcmatch | std::match_results<const wchar_t*> |
std::wstring | std::wsmatch | std::match_results<std::wstring::const_iterator> |
文字列型std::string
に対する検索を行う際には、一時オブジェクトによる検索が行えなくなるため注意が必要です。
std::smatch m;
/* C++14以降は利用できない */
// error: call to deleted function 'regex_search'
std::regex_search(std::string("s"), m, std::regex("."));
/* 代替処理 */
std::string s = "s";
std::regex_search(s, m, std::regex("."));
std::regex
などのbasic_regexをregex_iteratorに渡す際にも同様の問題が発生します。
std::string s = "s";
/* C++14以降は利用できない */
// error: call to deleted constructor of 'std::sregex_iterator' (aka 'regex_iterator<__wrap_iter<const char *> >')
std::sregex_iterator{begin(s), end(s), std::regex(".")};
// error: call to deleted constructor of 'std::cregex_iterator' (aka 'regex_iterator<const char *>')
std::cregex_iterator{"", "", std::regex(".")};
/* 代替処理 */
std::regex pt{"."};
std::sregex_iterator{begin(s), end(s), pt};
std::cregex_iterator{"", "", pt};
match_resultsで取得できる値や情報、応用方法
std::cmatch m;
std::regex_search("abcd", m, std::regex("(b)(c)")); // true
/* マッチ */
m.str() == "bc" ; // マッチした文字列
m.length() == 2 ; // マッチした文字列の長さ
m.position() == 1 ; // マッチした文字列の位置
m.empty() == false ; // マッチしたか否か
/* サブマッチ */
m.size() == 3 ; // サブマッチの数
m[0].str() == "bc" ; // サブマッチ(パターン全体)
m[1].str() == "b" ; // サブマッチ(`(b)`)
m[2].str() == "c" ; // サブマッチ(`(c)`)
m.str(2) == "c" ; // サブマッチ(`(c)`)
m[2].length() == 1 ; // サブマッチの文字列の長さ
m.prefix().str() == "a" ; // マッチした文字列の前方を表すサブマッチ
m.suffix().str() == "d" ; // マッチした文字列の後方を表すサブマッチ
m[0].second == m.suffix().first ; // マッチした場合は同じ値になる
/* サブマッチ - std::sub_match */
const std::sub_match<const char*>& sub_match = m[1];
std::string(sub_match) == "b" ; // true
std::string sub_match_str = m[1]; // "b" == sub_match_str
// スーパークラスのメンバ関数(`std::pair<T, U>::first`)
const char* first = sub_match.first;
const char* second = sub_match.second;
first == std::string("bcd") ; // true
second == std::string("cd") ; // true
/* 拡張for文/イテレータ */
for (const std::sub_match<const char*>& v : m) { // for (auto&& v : m) {}
// "2:bc", "1:b", "1:c" の順に出力
printf("%ld:%s\n", v.length(), v.str().c_str());
}
/* 型 */
using size_type = decltype(m.position());
static_assert(std::is_same<size_type, ptrdiff_t>::value, "");
static_assert(std::is_same<size_type, std::iterator_traits<const char*>::difference_type>::value, "");
std::cmatch results;
std::regex_search("ab", results, std::regex("a")) ;
results[0].matched == true ;
results[0].str() == "a" ;
auto prefix = results.prefix();
prefix.matched == false ;
auto suffix = results.suffix();
suffix.matched == true ;
suffix.str() == "b" ;
std::cmatch m;
std::regex_search("ABcdEF", m, std::regex("(c)(d)"));
m == {
matches: [
{str: "cd", first: "cdEF", second: "EF" , matched: true}
{str: "c", first: "cdEF", second: "dEF", matched: true}
{str: "d", first: "dEF" , second: "EF" , matched: true}
]
prefix: {str: "AB", first: "ABcdEF", second: "cdEF", matched: true}
suffix: {str: "EF", first: "EF" , second: "\0" , matched: true}
};