2013-11-27 4 views
1

Я желающих превратить std::string, такие как:Regex построить вектор из скобок

"{1, 2}, {one, two}, {123, onetwothree}" 

в std::vector из std::pairs из std::strings, который будет выглядеть примерно так:

std::vector<std::pair<std::string, std::string>> v = {{"1", "2"}, {"one", "two"}, {"123", "onetwothree"}}; 
// where, for instance 
v[0] == std::make_pair("1", "2"); // etc. 

Это походит случай, когда исходную std :: string можно было легко проанализировать с помощью std::regex, но я НЕ эксперт по регулярному выражению (или новичок), не говоря уже о эксперте std::regex. Какие-нибудь идеи для рецепта здесь?

+4

А вы пробовали, что до сих пор? – ScarletAmaranth

+0

Как насчет '' {1, {2, 3} {{a, b}}} "'? –

+0

Прямо сейчас, я использую собственные методы поиска std :: string для этого вручную. Не являясь человеком регулярного выражения, это показалось хорошим примером для начала, но примеры, которые я нашел, как правило, возвращают содержимое единственного соответствия фигурному скобку, но не повторяются через несколько совпадений матчей. – DiB

ответ

1

Шаблон соответствия довольно прост: «\ {\ s * (\ w +) \ s * \, \ s * (\ w +) \ s * \}", поэтому нам просто нужно выполнить цикл и собрать все Матчи. C++ 11 делает это довольно прямолинейно. Дайте этому выстрел:

std::string str = "{1, 2}, {one, two}, {123, onetwothree}"; 
std::vector<std::pair<std::string, std::string>> pairs; 
std::regex exp(R"(\{\s*(\w+)\s*\,\s*(\w+)\s*\})"); 
std::smatch sm; 
std::string::const_iterator cit = str.cbegin(); 
while (std::regex_search(cit, str.cend(), sm, exp)) { 
    if (sm.size() == 3) // 3 = match, first item, second item 
     pairs.emplace_back(sm[1].str(), sm[2].str()); 
    // the next line is a bit cryptic, but it just puts cit at the remaining string start 
    cit = sm[0].second; 
} 

EDIT: Разъяснение о том, как это работает: он соответствует одному шаблону, в то время, используя постоянный итератор, чтобы указать на оставшемся после каждого матча:

{1, 2}, {one, two}, {123, onetwothree} 
^ iterator cit 
-- regex_search matches "{1, 2}" sm[1] == "1", sm[2] == "2" 

{1, 2}, {one, two}, {123, onetwothree} 
    ^iterator cit 
-- regex_search matches "{one, two}" sm[1] == "one", sm[2] == "two" 

{1, 2}, {one, two}, {123, onetwothree} 
       ^iterator cit 
-- regex_search matches "{123, onetwothree}" sm[1] == "123", sm[2] == "onetwothree" 

{1, 2}, {one, two}, {123, onetwothree} 
            ^iterator cit 
-- regex_search returns false, no match 
+0

Я положил это, и он работал точно так, как я хотел. Я думаю, мой самый большой вопрос здесь заключается в понимании того, как регулярное выражение знает, чтобы искать N-количество совпадений. Я играл с другими идеями, основанными на запросах и комментариях других, и мне было трудно получить больше, чем внешний набор {}. – DiB

+0

AH!Поэтому регулярное выражение просто соответствует одному, но это итератор строки, который идет по строке, ища любые последующие совпадения. Спасибо за дополнительное объяснение. (Я должен был посмотреть, как итератор используется более подробно!) – DiB

+0

Я добавил объяснение, как это работает - регулярное выражение не соответствует совпадениям по N, а скорее соответствует первому совпадению. Затем мы используем итератор для итерации по остатку. Выполняя это в цикле, мы получаем каждое соответствие. –

3

В настоящее время, <regex> не работает с GCC, здесь есть версия для ускорения, скомпилированная с -lboost_regex.

boost capture подходит для этого случая, но по умолчанию он не включен.

Вот оригинальный пост: Boost C++ regex - how to get multiple matches

#include <iostream> 
#include <string> 
#include <boost/regex.hpp> 

using namespace std; 

int main() 
{ 
    string str = "{1, 2}, {one, two}, {123, onetwothree}"; 

    boost::regex pair_pat("\\{[^{}]+\\}"); 
    boost::regex elem_pat("\\s*[^,{}]+\\s*"); 

    boost::sregex_token_iterator end; 

    for(boost::sregex_token_iterator iter(str.begin(), str.end(), pair_pat, 0); 
     iter != end; ++iter) { 

    string pair_str = *iter; 
    cout << pair_str << endl; 

    for (boost::sregex_token_iterator it(pair_str.begin(), pair_str.end(), elem_pat, 0); 
     it != end; ++it) 
     cout << *it << endl; 
    } 

    return 0; 
} 
Смежные вопросы