O que std :: match_results :: size retorna?

Estou um pouco confuso sobre o seguinte código C ++ 11:

#include  #include  #include  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; } 

Eu esperaria que ele imprimisse 3 mas em vez disso eu obtenho 1 . Estou esquecendo de algo?

Você obtém 1 porque regex_search retorna apenas 1 correspondência e size() retornará o número de grupos de captura + o valor total da correspondência.

Suas matches são …:

Objeto de um tipo match_results (como cmatch ou smatch) preenchido por essa function com informações sobre os resultados da correspondência e quaisquer submaturas encontradas.

Se [a pesquisa regex for] bem-sucedida, ela não estará vazia e conterá uma série de objects sub_match: o primeiro elemento sub_match corresponde à correspondência inteira e, se a expressão regex contiver subexpressões a serem correspondidas (isto é, delimitadas por parênteses grupos), suas correspondentes sub-correspondências são armazenadas como elementos sub_match sucessivos no object match_results.

Aqui está um código que encontrará várias correspondências:

 #include  #include  #include  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; } 

Veja a demonstração do IDEONE retornando abc 3 vezes.

Como este método destrói a string de input, aqui está outra alternativa baseada no std::sregex_iterator ( std::wsregex_iterator deve ser usado quando seu assunto é um object 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; } 

Veja a demonstração do IDEONE , retornando

 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 

O que você está perdendo é que as matches são preenchidas com uma input para cada grupo de captura (incluindo toda a substring correspondida como a 0ª captura).

Se você escreve

 std::regex needle("a(b)c"); 

então você obterá matches.size()==2 , com matches[0]=="abc" e matches[1]=="b" .

A solução do @stribizhev tem uma complexidade quadrática do pior caso para expressões regulares sãs. Para os insanos (por exemplo, “y *”), não termina. Em alguns aplicativos, esses problemas podem ser ataques de negação de serviço esperando para acontecer. Aqui está uma versão fixa:

 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; } 

De acordo com minha preferência pessoal, isso vai encontrar n + 1 correspondências de um regex vazio em uma string de comprimento n. Você também pode simplesmente sair do loop após uma partida vazia.

Se você quiser comparar o desempenho de uma string com milhões de correspondências, adicione as seguintes linhas após a definição de str (e não se esqueça de ativar as otimizações), uma vez para cada versão:

 for (int j = 0; j < 20; ++j) str = str + str;