Что возвращает std::match_results::size?
Я немного озадачен следующим кодом C++11:
#include <iostream>
#include <string>
#include <regex>
int main()
{
std::string haystack("abcdefabcghiabc");
std::regex needle("abc");
std::smatch matches;
std::regex_search(haystack, matches, needle);
std::cout << matches.size() << std::endl;
}
Я ожидаю, что это распечатает 3
но вместо этого я получаю 1
, Я что-то пропустил?
3 ответа
Ты получаешь 1
так как regex_search
возвращает только 1 совпадение иsize()
вернет количество групп захвата + все значение совпадения.
Вашmatches
является...:
Объект типа match_results(например, cmatch или smatch), который заполняется этой функцией информацией о результатах сопоставления и любых найденных совпадениях.
Если [поиск по регулярному выражению] успешен, он не является пустым и содержит серию объектов sub_match: первый элемент sub_match соответствует всему совпадению, и, если выражение регулярного выражения содержит подвыражения, которые должны быть сопоставлены (то есть разделены скобками групп), их соответствующие суб-совпадения сохраняются как последовательные элементы sub_match в объекте match_results.
Вот код, который найдет несколько совпадений:
#include <string>
#include <iostream>
#include <regex>
using namespace std;
int main() {
string str("abcdefabcghiabc");
int i = 0;
regex rgx1("abc");
smatch smtch;
while (regex_search(str, smtch, rgx1)) {
std::cout << i << ": " << smtch[0] << std::endl;
i += 1;
str = smtch.suffix().str();
}
return 0;
}
Смотрите возвращение демо IDEONE abc
три раза.
Поскольку этот метод уничтожает входную строку, здесь есть еще одна альтернатива, основанная на std::sregex_iterator
(std::wsregex_iterator
следует использовать, когда ваш предмет std::wstring
объект):
int main() {
std::regex r("ab(c)");
std::string s = "abcdefabcghiabc";
for(std::sregex_iterator i = std::sregex_iterator(s.begin(), s.end(), r);
i != std::sregex_iterator();
++i)
{
std::smatch m = *i;
std::cout << "Match value: " << m.str() << " at Position " << m.position() << '\n';
std::cout << " Capture: " << m[1].str() << " at Position " << m.position(1) << '\n';
}
return 0;
}
Смотрите IDEONE демо, возвращаясь
Match value: abc at Position 0
Capture: c at Position 2
Match value: abc at Position 6
Capture: c at Position 8
Match value: abc at Position 12
Capture: c at Position 14
Что вы упускаете, так это matches
заполняется одной записью для каждой группы захвата (включая всю подобранную подстроку в качестве 0-го захвата).
Если ты пишешь
std::regex needle("a(b)c");
тогда вы получите matches.size()==2
, с matches[0]=="abc"
, а также matches[1]=="b"
,
Решение @stribizhev имеет квадратичную сложность в худшем случае для правильных регулярных выражений. Для безумных (например, "y*") это не заканчивается. В некоторых приложениях такими проблемами могут быть DoS-атаки, ожидающие своего появления. Вот исправленная версия:
string str("abcdefabcghiabc");
int i = 0;
regex rgx1("abc");
smatch smtch;
auto beg = str.cbegin();
while (regex_search(beg, str.cend(), smtch, rgx1)) {
std::cout << i << ": " << smtch[0] << std::endl;
i += 1;
if ( smtch.length(0) > 0 )
std::advance(beg, smtch.length(0));
else if ( beg != str.cend() )
++beg;
else
break;
}
Согласно моим личным предпочтениям, это найдет n+1 совпадений пустого регулярного выражения в строке длины n. Вы также можете просто выйти из цикла после пустого совпадения.
Если вы хотите сравнить производительность строки с миллионами совпадений, добавьте следующие строки после определения str
(и не забудьте включить оптимизацию), один раз для каждой версии:
for (int j = 0; j < 20; ++j)
str = str + str;