¿Qué devuelve std :: match_results :: size?

Estoy un poco confundido sobre el siguiente 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; } 

Esperaría que imprimiera 3 pero en cambio obtengo 1 . ¿Me estoy perdiendo de algo?

regex_search 1 porque regex_search devuelve solo 1 coincidencia, y size() devolverá el número de grupos de captura + el valor de coincidencia completo.

Tus matches son …

Objeto del tipo match_results (como cmatch o smatch) que completa esta función con información sobre los resultados del partido y cualquier subcoincidencia encontrada.

Si [la búsqueda de expresiones regulares es] exitosa, no está vacía y contiene una serie de objetos sub_match: el primer elemento sub_match corresponde a la coincidencia completa y, si la expresión de expresiones regulares contiene subexpresiones para ser emparejadas (es decir, delimitadas por paréntesis) grupos), sus subclases correspondientes se almacenan como elementos sub_match sucesivos en el objeto match_results.

Aquí hay un código que encontrará múltiples coincidencias:

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

Vea la demostración de IDEONE que regresa abc 3 veces.

Como este método destruye la cadena de entrada, aquí hay otra alternativa basada en std::sregex_iterator ( std::wsregex_iterator debe usarse cuando su sujeto es un objeto 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; } 

Ver demostración IDEONE , regresando

 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 

Lo que se está perdiendo es que las matches se llenan con una entrada para cada grupo de captura (incluida la subcadena completa coincidente como la 0ª captura).

Si tú escribes

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

entonces obtendrás matches.size()==2 , con matches[0]=="abc" , y matches[1]=="b" .

La solución de @ stribizhev tiene la complejidad cuadrática más desfavorable para expresiones regulares sanas. Para los insanos (por ejemplo, “y *”), no termina. En algunas aplicaciones, estos problemas podrían ser ataques DoS en espera de ocurrir. Aquí hay una versión fija:

 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 acuerdo con mis preferencias personales, esto encontrará n + 1 coincidencias de una expresión regular vacía en una cadena de longitud n. También puede simplemente salir del bucle después de una coincidencia vacía.

Si desea comparar el rendimiento de una cadena con millones de coincidencias, agregue las siguientes líneas después de la definición de str (y no olvide activar las optimizaciones), una vez para cada versión:

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