C++11: Безопасная практика с регулярным выражением двух возможных количеств совпадений

С этим регулярным выражением я бы хотел сопоставить время с полем миллисекунд (мс) или без него. Для полноты я напишу здесь регулярное выражение (я удалил якоря в регулярном выражении для включения многострочного):

^(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(?:|(?:\.)([0-9]{1,6}))$

Я вроде не понимаю поведение C++ в этом. Теперь вы видите в regex101, количество групп захвата зависит от строки. Если нет ms, это 3+1 (так как C++ использует match[0] для сопоставленного шаблона), а если есть ms, то это 4+1. Но тогда в этом примере:

std::regex timeRegex = std::regex(R"(^(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(?:|(?:\.)([0-9]{1,6}))$)");
std::smatch m;
std::string strT = std::string("12:00:09");
bool timeMatch = std::regex_match(strT, m, timeRegex);
std::cout<<m.size()<<std::endl;
if(timeMatch)
{
    std::cout<<m[0]<<std::endl;
    std::cout<<m[1]<<std::endl;
    std::cout<<m[2]<<std::endl;
    std::cout<<m[3]<<std::endl;
    std::cout<<m[4]<<std::endl;
}

Мы видим, что m.size() всегда 5, есть ли поле мс или нет! m[4] пустая строка, если нет поля ms. Это поведение по умолчанию в регулярном выражении C++? Или я должен попробовать / поймать (или другие меры безопасности), если сомневаетесь в размере? Я имею в виду... даже размер здесь немного вводит в заблуждение!

3 ответа

Решение

m.size() всегда будет количество отмеченных подвыражений в вашем выражении плюс 1 (для всего выражения).

В вашем коде у вас есть 4 помеченных подвыражения, независимо от того, совпадают они или нет, не влияет на размер m,

Если вы хотите сейчас, если есть миллисекунды, вы можете проверить:

m[4].matched
m.size();// Returns the number of match results. 
         // a string is allocated for each 'Capture Group' 
         // and filled with the match substring. 

Так как smatch является match_results

(см.) http://www.cplusplus.com/reference/regex/match_results/

size возвращает количество совпадений ALLOCATED, которое зависит от количества групп захвата, содержащихся в вашем регулярном выражении.

Группы захвата:

Скобки группируют регулярное выражение между ними. Они фиксируют текст, соответствующий регулярному выражению внутри них, в пронумерованную группу, которую можно повторно использовать с пронумерованной обратной ссылкой. Они позволяют применять операторы регулярных выражений ко всему сгруппированному регулярному выражению.

http://www.regular-expressions.info/refcapture.html

Вот почему ваш размер будет выделен как 5, независимо от того, что вы в конечном итоге заполните regex_match(). Как и у других, есть Notex, пятый - полный матч.

Смотрите: Что возвращает std::match_results::size?

std::smatch (ака std::match_results<std::string::const_iterator>) это в основном контейнер, который содержит элементы типа std::sub_match, Первый элемент - это результаты сопоставления для вашего полного выражения регулярного выражения, а последующие содержат совпадения для каждого подвыражения. Поскольку у вас есть 4 подвыражения, если вы используете шаблон, вы получите 5 результатов (4 + полное соответствие).

Другие вопросы по тегам