C ++ :: Boost :: Regex Итерация по подстатьям - PullRequest
6 голосов
/ 27 апреля 2010

Я использую именованные группы захвата с Boost Regex / Xpressive.

Я хотел бы перебрать все подспаривания и получить как значение, так и KEY каждого подспаривания (т.е. what ["type"]).

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

Ответы [ 2 ]

3 голосов
/ 04 ноября 2013

С Boost 1.54.0 это еще сложнее, потому что имена захвата даже не сохраняются в результатах. Вместо этого Boost просто хэширует имена перехвата и сохраняет хеш (int) и связанные с ним указатели на исходную строку.

Я написал небольшой класс, полученный из boost::smatch, который сохраняет имена перехвата и предоставляет для них итератор.

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

Класс принимает регулярное выражение, содержащее именованные группы захвата, в своем конструкторе. Используйте класс так:

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();
2 голосов
/ 24 ноября 2010

Посмотрев на это более часа, я чувствую себя довольно уверенно, говоря: «Это невозможно сделать, капитан». Даже в буст-коде они выполняют поиск по частному вектору named_marks_ при поиске. Это просто не настроено, чтобы позволить это. Я бы сказал, что лучше всего было бы перебрать те, которые, по вашему мнению, должны быть там, и поймать исключение для тех, которые не найдены.

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()];
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...