2010-04-27 23 views
5

Estoy utilizando Grupos de captura con nombre con Boost Regex/Xpressive.C++ :: Boost :: Regex Iterar sobre las subcompetencias

Me gustaría iterar sobre todas las subcompetencias, y obtener tanto el valor como la CLAVE de cada subcoincidencia (es decir, qué ["tipo"]).

sregex pattern = sregex::compile( "(?P<type>href|src)=\"(?P<url>[^\"]+)\"" ); 

sregex_iterator cur(web_buffer.begin(), web_buffer.end(), pattern); 
sregex_iterator end; 

for(; cur != end; ++cur){ 
    smatch const &what = *cur; 

    //I know how to access using a string key: what["type"] 
    std::cout << what[0] << " [" << what["type"] << "] [" << what["url"] <<"]"<< std::endl; 

    /*I know how to iterate, using an integer key, but I would 
     like to also get the original KEY into a variable, i.e. 
     in case of what[1], get both the value AND "type" 
    */ 
    for(i=0; i<what.size(); i++){ 
     std::cout << "{} = [" << what[i] << "]" << std::endl; 
    } 

    std::cout << std::endl; 
} 

Respuesta

2

Después de mirar esto por más de una hora, me siento bastante seguro diciendo: "no se puede hacer capitán". Incluso en el código boost, iteran sobre el vector private_marks_marks_ al hacer la búsqueda. Simplemente no está configurado para permitir eso. Yo diría que la mejor opción sería repetir las que crees que deberían estar allí y atrapar la excepción para las que no se encuentran.

const_reference at_(char_type const *name) const 
{ 
    for(std::size_t i = 0; i < this->named_marks_.size(); ++i) 
    { 
     if(this->named_marks_[i].name_ == name) 
     { 
      return this->sub_matches_[ this->named_marks_[i].mark_nbr_ ]; 
     } 
    } 
    BOOST_THROW_EXCEPTION(
     regex_error(regex_constants::error_badmark, "invalid named back-reference") 
    ); 
    // Should never execute, but if it does, this returns 
    // a "null" sub_match. 
    return this->sub_matches_[this->sub_matches_.size()]; 
} 
3

Con Boost 1.54.0 esto es aún más difícil porque los nombres de captura ni siquiera están almacenados en los resultados. En su lugar, Boost solo hash los nombres de captura y almacena el hash (un int) y los punteros asociados a la cadena original.

He escrito una clase pequeña derivada de boost::smatch que guarda nombres de captura y les proporciona un iterador.

class namesaving_smatch : public smatch 
{ 
public: 
    namesaving_smatch(const regex& pattern) 
    { 
     std::string pattern_str = pattern.str(); 
     regex capture_pattern("\\?P?<(\\w+)>"); 
     auto words_begin = sregex_iterator(pattern_str.begin(), pattern_str.end(), capture_pattern); 
     auto words_end = sregex_iterator(); 

     for (sregex_iterator i = words_begin; i != words_end; i++) 
     { 
      std::string name = (*i)[1].str(); 
      m_names.push_back(name); 
     } 
    } 

    ~namesaving_smatch() { } 

    std::vector<std::string>::const_iterator names_begin() const 
    { 
     return m_names.begin(); 
    } 

    std::vector<std::string>::const_iterator names_end() const 
    { 
     return m_names.end(); 
    } 

private: 
    std::vector<std::string> m_names; 
}; 

La clase acepta la expresión regular que contiene los grupos de captura nombrados en su constructor. Use la clase como tal:

namesaving_smatch results(re); 
if (regex_search(input, results, re)) 
    for (auto it = results.names_begin(); it != results.names_end(); ++it) 
     cout << *it << ": " << results[*it].str();