Строка "I am 5 years old"

Регулярное выражение "(?!am )\d"

Если вы перейдете на http://regexr.com/ и примените регулярное выражение к строке, вы получите 5. Я хотел бы получить этот результат с помощью std :: regex, но я не понимаю, как использовать результаты совпадений, и, вероятно, также необходимо изменить регулярное выражение.

std::regex expression("(?!am )\\d");
std::smatch match;
std::string what("I am 5 years old.");
if (regex_search(what, match, expression))
{
     //???
}
18
Kimi 14 Июн 2017 в 12:27
1
Ваше регулярное выражение неверно, поскольку 5 никогда не будет равно a. (?!am )\d совпадает с \d.
 – 
Wiktor Stribiżew
14 Июн 2017 в 12:28
Мне нужно поставить цифру после слова «я» и пробел.
 – 
Kimi
14 Июн 2017 в 12:30
1
Почему бы просто не выполнить поиск "I am (\d)+ years old" с помощью регулярного выражения и не использовать захват?
 – 
Mateen Ulhaq
14 Июн 2017 в 12:31
Я просто привел тривиальный пример, цель которого - перенести рабочее регулярное выражение на C ++. На самом деле у нас есть текст с волшебным словом, за которым следует пробел и число. Мне нужно получить этот номер.
 – 
Kimi
14 Июн 2017 в 12:34

1 ответ

Лучший ответ

std::smatch - это экземпляр шаблона класса match_results для совпадений на строковые объекты (с типом итератора string::const_iterator). Члены этого класса описаны для match_results, но используют string::const_iterator в качестве параметра шаблона BidirectionalIterator.

std::match_results поддерживает operator[]:

Если n > 0 и n < size(), возвращает ссылку на std::sub_match, представляющая часть целевой последовательности, которой соответствует n -й захваченный отмеченное подвыражение).

Если n == 0, возвращает ссылку на std::sub_match представляющая часть целевой последовательности, совпадающую со всем совпадающим регулярным выражением.

если n >= size(), возвращает ссылку на std::sub_match представляет несопоставленное подвыражение (пустой поддиапазон целевой последовательности).

В вашем случае regex_search находит только первое совпадение , а затем match[0] содержит весь текст совпадения, match[1] будет содержать текст, захваченный первой группой захвата ( первая часть шаблона в скобках) и т. д. Однако в этом случае ваше регулярное выражение не содержит групп захвата.

Здесь вам нужно использовать механизм захвата , поскольку std::regex не поддерживает взгляд сзади . Вы использовали опережающий просмотр, который проверяет текст, который непосредственно следует за текущим местоположением, а имеющееся у вас регулярное выражение не выполняет то, что вы думаете.

Итак, используйте следующий код:

#include <regex>
#include <string>
#include <iostream>
using namespace std;

int main() {
    std::regex expression(R"(am\s+(\d+))");
    std::smatch match;
    std::string what("I am 5 years old.");
    if (regex_search(what, match, expression))
    {
         cout << match.str(1) << endl;
    }
    return 0;
}

Здесь шаблон - am\s+(\d+)". Он сопоставляет am, 1+ пробелов, а затем захватывает 1 или более цифр с (\d+). Внутри кода match.str(1) разрешает доступ к значениям, которые фиксируются с помощью групп захвата. Поскольку в шаблоне только один (...), одна группа захвата, ее идентификатор равен 1. Итак, str(1) возвращает текст, захваченный в эту группу.

Необработанный строковый литерал (R"(...)") позволяет использовать одиночную обратную косую черту для экранирования регулярных выражений (например, \d, \s и т. Д.).

7
Community 20 Июн 2020 в 12:12
std::regex_search возвращает false при отсутствии соответствие. Итак, я думаю, что этот случай описан в моем коде выше, поскольку match.str(1) не будет выполняться, если совпадение не будет найдено. См. эту демонстрацию без совпадений.
 – 
Wiktor Stribiżew
14 Июн 2017 в 12:48
Спасибо, по какой-то причине мне нужно позвонить match.str(2), чтобы получить цифру. match.str(1) возвращает "am 5". Я использую VS2015 с набором инструментов платформы Visual Studio 2012 (v110).
 – 
Kimi
14 Июн 2017 в 12:58
1
Это потому, что у вас может не быть доступа к необработанным строковым литералам. Если вы используете набор инструментов VS2015, вы будете и `std :: regex expression (R" (am \ s + (\ d +)) ");` захватит число в группу 1. Вы должны использовать "(am\\s+(\\d+))", a обычный строковый литерал, в котором нельзя использовать первый ( и последний ). Удалите их, и вы получите результат в Группе 1. R"(am\s+(\d+))" = "am\\s+(\\d+)".
 – 
Wiktor Stribiżew
14 Июн 2017 в 13:00
Да, он не будет компилироваться с R"". Мне пришлось удалить R и добавить extra \, но я забыл удалить extra (и). Все работает, спасибо большое.
 – 
Kimi
14 Июн 2017 в 13:09
Что ты имеешь в виду? Есть обратные ссылки?
 – 
Passer By
14 Июн 2017 в 13:49