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

контекст. Я разрабатываю движок Lexer / Tokenizing, который будет использовать регулярное выражение в качестве бэкэнда. Лексер принимает правила, которые определяют типы / идентификаторы токенов, например,

<identifier> = "\\b\\w+\\b",

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

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

Таким образом, возникает проблема этого вопроса — как получить идентификатор группы?

Подобный вопрос здесь, но это не дает решения моей конкретной проблемы.

Именно моя проблема Вот, но это в JS, и мне нужно решение C / C ++.

Допустим, у меня есть регулярное выражение, состоящее из групп захвата, разделенных OR:

(\\b[a-zA-Z]+\\b)|(\\b\\d+\\b)

который соответствует целым числам или альфа-словам.

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

foo bar 123

3 итерации будут сделаны. Групповые индексы совпадений каждой итерации будут 0 0 1потому что первые два совпадения соответствуют первой группе захвата, а последнее совпадение соответствует второй группе захвата.

Я знаю что в стандарте std::regex библиотека это не совсем возможно (regex_token_iterator это не решение, потому что мне не нужно пропускать какие-либо совпадения).

У меня мало знаний о boost::regex или библиотека регулярных выражений PCRE.

Каков наилучший способ выполнить эту задачу? Какую библиотеку и метод использовать?

2

Решение

Вы можете использовать sregex_iterator чтобы получить все совпадения, и когда есть совпадение, вы можете проанализировать std::match_results структура и только захватить значение ID-1 группы, которая не является пустой (только одна группа, которая соответствует, будет непустой):

std::regex r(R"((\b[[:alpha:]]+\b)|(\b\d+\b))");
std::string s = "foo bar 123";
for(std::sregex_iterator i = std::sregex_iterator(s.begin(), s.end(), r);
i != std::sregex_iterator();
++i)
{
std::smatch m = *i;
std::cout << "Match value: " << m.str() << " at Position " << m.position() << '\n';

for(auto index = 1; index < m.size(); ++index ){
if (!m[index].str().empty()) {
std::cout << "Capture group ID: " << index-1 << std::endl;
break;
}
}
}

Увидеть C ++ demo. Выход:

Match value: foo at Position 0
Capture group ID: 0
Match value: bar at Position 4
Capture group ID: 0
Match value: 123 at Position 8
Capture group ID: 1

Обратите внимание, что R"(...)" является необработанным строковым литералом, нет необходимости удваивать обратную косую черту внутри

Также, index установлен в 1 в начале for Цикл, потому что 0-я группа — это полное совпадение, но вы хотите, чтобы идентификаторы групп были на основе нуля, поэтому 1 вычитается позже.

1

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector