2015-05-02 2 views
1

В настоящее время я пытаюсь создать регулярное выражение, которое соответствует параметрам URL и извлекает их.C++ Regex: non-greedy match

Например, если я получил следующие параметры строки ?param1=someValue&param2=someOtherValue, std::regex_match следует извлечь следующее содержание:

  • param1
  • some_content
  • param2
  • some_other_content

Af Попробуйте различные шаблоны регулярных выражений, я, наконец, построил один, соответствующий тому, что я хочу: std::regex("(?:[\\?&]([^=&]+)=([^=&]+))*").

Если я возьму предыдущий пример, std::regex_match соответствует ожиданиям. Однако он не извлекает ожидаемые значения, сохраняя только последние зафиксированные значения.

Например, следующий код:

std::regex paramsRegex("(?:[\\?&]([^=&]+)=([^=&]+))*"); 
std::string arg = "?param1=someValue&param2=someOtherValue"; 
std::smatch sm; 

std::regex_match(arg, sm, paramsRegex); 
for (const auto &match : sm) 
    std::cout << match << std::endl; 

даст следующий вывод:

param2 
someOtherValue 

Как вы можете видеть, param1 и его значение пропускаются и не учитываются.

После поиска в google я обнаружил, что это связано с жадным захватом, и я изменил свое регулярное выражение на "(?:[\\?&]([^=&]+)=([^=&]+))\\*?", чтобы включить нежеланный захват.

Это регулярное выражение работает хорошо, когда я пытаюсь его на rubular, но он не совпадает, когда я использую его в C++ (std::regex_match возвращает false и ничего не фиксируется).

Я пробовал разные варианты std::regex_constants (различные грамматики регулярных выражений с использованием std::regex_constants::grep, std::regex_constants::egrep, ...), но результат тот же.

Кто-нибудь знает, как сделать непривлекательный захват регулярных выражений на C++?

+4

Каждый repeatition из группы захвата перезаписывать предыдущий. Вам нужно удалить квантификатор '[? &] ([^ =] +) = ([^ &] +)' И использовать итератор regex для получения разных совпадений: http://en.cppreference.com/w/cpp/regex/regex_iterator. Это не жадная/не жадная проблема. –

+0

Спасибо за объяснения: я пробовал с regex_iterators, и он работает хорошо! –

ответ

3

Как Casimir et Hippolyte объяснил в своем comment, мне просто нужно:

  • удалить квантор
  • Используйте std::regex_iterator

Это дает мне следующий код:

std::regex paramsRegex("[\\?&]([^=]+)=([^&]+)"); 
std::string url_params = "?key1=val1&key2=val2&key3=val3&key4=val4"; 
std::smatch sm; 

auto params_it = std::sregex_iterator(url_params.cbegin(), url_params.cend(), paramsRegex); 
auto params_end = std::sregex_iterator(); 

while (params_it != params_end) { 
    auto param = params_it->str(); 

    std::regex_match(param, sm, paramsRegex); 
    for (const auto &s : sm) 
     std::cout << s << std::endl; 

    ++params_it; 
} 

И вот вывод:

?key1=val1 
key1 
val1 
&key2=val2 
key2 
val2 
&key3=val3 
key3 
val3 
&key4=val4 
key4 
val4 

оригинальное регулярное выражение (?:[\\?&]([^=&]+)=([^=&]+))* просто переоделись в [\\?&]([^=]+)=([^&]+).

Затем, используя std::sregex_iterator, я получаю итератор по каждой группе (?key1=val1, &key2=val2, ...).

Наконец, позвонив по std::regex_match на каждую подстроку, я могу получить значения параметров.

0

Попробуйте использовать match_results :: префикс/суффикс:

string match_expression("your expression"); 
smatch result; 
regex fnd(match_expression, regex_constants::icase); 
while (regex_search(in_str, result, fnd, std::regex_constants::match_any)) 
{ 
    for (size_t i = 1; i < result.size(); i++) 
    {   
     std::cout << result[i].str(); 
    } 
    in_str = result.suffix(); 
}