контекст. Я разрабатываю движок 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.
Каков наилучший способ выполнить эту задачу? Какую библиотеку и метод использовать?
Вы можете использовать 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
вычитается позже.
Других решений пока нет …