tr1::regex regex_search проблема

Я использую tr1::regex, чтобы попытаться извлечь некоторые совпадения из строки. Пример строки может быть

asdf werq "one two three" asdf

И я хотел бы выйти из этого:

asdf  
werq  
one two three  
asdf  

С материалами в кавычках, сгруппированными вместе, поэтому я пытаюсь использовать регулярное выражение \"(.+?)\"|([^\\s]+). Код, который я использую:

cmatch res;
regex reg("\"(.+?)\"|([^\\s]+)", regex_constants::icase);
regex_search("asdf werq \"one two three\" asdf", res, reg);

cout << res.size() << endl;
for (unsigned int i = 0; i < res.size(); ++k) {
    cout << res[i] << endl;
}

но это выводит

3
asdf

asdf

Что я делаю не так?


person Thomas T.    schedule 29.08.2010    source источник


Ответы (2)


Похоже, ваш движок регулярных выражений не поддерживает проверки назад. Чтобы избежать использования lookbehind, вы можете попробовать следующее:

"([^"]*)"|(\S+)

или цитата:

"\"([^\"]*)\"|(\\S+)"

Это регулярное выражение будет работать, но каждое совпадение будет иметь два захвата, один из которых будет пустым (либо первый — в случае слова без кавычек, либо второй — в случае строки в кавычках).

Чтобы иметь возможность использовать это, вам нужно перебрать все совпадения и для каждого совпадения использовать непустой захват.

Я недостаточно знаю о TR1, поэтому я не знаю точно, как перебирать все совпадения. Но если я не ошибаюсь, res.size() всегда будет равно 3.

Например, для строки asdf "one two three" werq первым совпадением будет:

res[0] = "asdf"              // the entire match
res[1] = ""                  // the first capture
res[2] = "asdf"              // the second capture

Второй матч будет:

res[0] = "\"one two three\"" // the entire match including leading/trailing quotes
res[1] = "one two three"     // the first capture
res[2] = ""                  // the second capture

и третье совпадение будет:

res[0] = "werq"              // the entire match
res[1] = ""                  // the first capture
res[2] = "werq"              // the second capture

ХТН.

person Roy Sharon    schedule 29.08.2010
comment
Как тогда мне получить совпадения, как вы сказали, если я использую итератор? Вы используете итератор в стиле for (std::tr1::sregex_token_iterator i(str.begin(), str.end(), reg); i != end; ++i) { cout ‹‹ *i; } На самом деле у вас нет выбора, получите ли вы полное совпадение, первый захват или второй захват, как я вижу. - person Thomas T.; 29.08.2010
comment
А как насчет следующего: for (std::tr1::sregex_token_iterator i(str.begin(), str.end(), reg); i != end; ++i) { cout << ((*i)[1] || (*i)[2]); }? Я не могу проверить, компилируется ли это, не говоря уже о запуске, но идея в том, что *i — это объект с оператором индексации, который должен дать вам захваты. - person Roy Sharon; 29.08.2010

Вместо этого вы можете попробовать следующее регулярное выражение:

(?<=")[^"]*(?=")|[^"\s]\S*

При цитировании его, конечно, нужно экранировать:

"(?<=\")[^\"]*(?=\")|[^\"\\s]\\S*"

Кстати, код, который вы использовали, вероятно, соответствует только первому слову в целевой строке, поскольку он не использует match_any. 3 элемента, которые вы получаете в результате, это, вероятно, (1) полное совпадение, (2) первый захват, который пуст, и (3) второй захват, который является источником совпадения.

person Roy Sharon    schedule 29.08.2010
comment
На самом деле, когда я использую это регулярное выражение, когда я запускаю программу, это выводится на консоль: это приложение запросило среду выполнения, чтобы завершить его необычным образом. Пожалуйста, свяжитесь с... бла-бла-бла, и он вылетает. - person Thomas T.; 29.08.2010
comment
У меня нет рабочей среды, в которой я мог бы это проверить, но я протестировал регулярное выражение как с Java, так и с C#, и оно не дало сбоев. Используйте синтаксис_option_type=extended, чтобы убедиться, что он соответствует стандартному синтаксису расширенных регулярных выражений. (Кстати, я сделал небольшое исправление в первой части регулярного выражения, чтобы предотвратить захват пробела после конца слова в кавычках.) - person Roy Sharon; 29.08.2010
comment
Вам предлагается поиграть с регулярным выражением здесь: myregextester.com/?r=a9e366fd - person Roy Sharon; 29.08.2010
comment
Я изменил его на регулярное выражение reg((?‹=\)[^\]*(?=\)|[^\\\s]\\S*, regex_constants::syntax_option_type::extended); и я снова получил эту ошибку :( Любая идея, почему? - person Thomas T.; 29.08.2010
comment
Странная ошибка: независимо от того, какое регулярное выражение я использую, regex_constants::syntax_option_type::extended всегда приводит к сбою. Если я уберу это и удалю (?‹=\) из вашего регулярного выражения, он не рухнет. - person Thomas T.; 29.08.2010
comment
Подтверждено, regex_constants::extended вызывает сбой всех регулярных выражений. Без второго аргумента я могу использовать ваше регулярное выражение, если я уберу просмотр назад, но это даст неправильные результаты. - person Thomas T.; 29.08.2010
comment
Я понимаю. Хорошо, есть еще один вариант, который немного сложнее, но не требует проверки назад. Я добавлю его через несколько минут к решению выше. - person Roy Sharon; 29.08.2010
comment
Если я использую \(.+?)\|([^\\s]+) и for (std::tr1::sregex_token_iterator i(str.begin(), str.end(), reg); i != end; ++i), стиль итератора, он работает нормально, за исключением случаев, когда он соответствует чему-то в кавычках, он по какой-то причине включает кавычки. - person Thomas T.; 29.08.2010
comment
Да, потому что вы получаете полное совпадение, включая цитаты. Смотрите объяснение в другом решении, которое я опубликовал. - person Roy Sharon; 29.08.2010
comment
Кстати, \"[^\"]*\" лучше, чем \".*?\", потому что он (1) также ловит \n внутри кавычек и (2) несколько быстрее. Кроме того, [^\\s] эквивалентно \\S. - person Roy Sharon; 29.08.2010