Класс match_results: результаты поиска

Если в функциях regex_match() и regex_search() указать параметр match, то станет доступной дополнительная информация о совпадении с шаблоном в виде объекта шаблонного класса match_results:

template<typename _Bi_iter,
         typename _Alloc = allocator<sub_match<_Bi_iter> > >
   class match_results
      : private std::vector<sub_match<_Bi_iter>, _Alloc>

На практике удобно воспользоваться псевдонимами cmatch, wcmatch, smatch или wsmatch:

typedef match_results<const char*> cmatch;
typedef match_results<const wchar_t*> wcmatch;
typedef match_results<string::const_iterator> smatch;
typedef match_results<wstring::const_iterator> wsmatch;

Пример создания экземпляра класса smatch:

std::smatch m;

Класс match_results содержит следующие основные методы:

  • empty() — возвращает значение true, если результатов поиска нет, и false — если результаты поиска доступны. Прототип метода:
bool empty() const;
  • size() — возвращает количество доступных результатов. Прототип метода:
size_type size() const;
  • str() — возвращает фрагмент по индексу в виде объекта класса basic_string. Прототип метода:
string_type str(size_type sub=0) const;
typedef basic_string<char_type> string_type;

Если параметр не указан или указано значение 0, то метод возвращает фрагмент, полностью совпадающий с шаблоном. Если указано число больше 0, то возвращается фрагмент, заключенный внутри шаблона в круглые скобки, с указанным индексом.

Вместо использования метода str() можно указать индекс фрагмента внутри квадратных скобок:

const_reference operator[](size_type sub) const;
typedef const value_type &const_reference;
typedef sub_match<_Bi_iter> value_type;

Получим все три числа по отдельности, используя класс cmatch:

std::regex rgx("([0-9]+) ([0-9]+) ([0-9]+)");
std::cmatch m;
std::regex_search("12 34 56", m, rgx);
if (!m.empty()) {
   for (size_t i = 0, size = m.size(); i < size; ++i) {
      std::cout << m[i] << ' ' << m.str(i) << std::endl;
   }
}

Результат:

12 34 56 12 34 56
12 12
34 34
56 56

Перебрать все фрагменты можно также с помощью цикла for each:

std::regex rgx("([0-9]+) ([0-9]+) ([0-9]+)");
std::cmatch m;
if (std::regex_search("12 34 56", m, rgx)) {
   for (auto i : m) {
      std::cout << i.str() << std::endl;
   }
}

Результат:

12 34 56
12
34
56
  • length() — возвращает длину фрагмента с указанным индексом. Прототип метода:
difference_type length(size_type sub=0) const;
  • position() — возвращает позицию фрагмента с указанным индексом внутри строки. Прототип метода:
difference_type position(size_type sub=0) const;

Получим длину и позицию всех найденных фрагментов:

std::regex rgx("([0-9]+) ([0-9]+) ([0-9]+)");
std::cmatch m;
if (std::regex_search("1 23 456", m, rgx)) {
   for (size_t i = 0, size = m.size(); i < size; ++i) {
      std::cout << m.str(i) << ": length=" << m.length(i)
                << " position=" << m.position(i) << std::endl;
   }
}

Результат:

1 23 456: length=8 position=0
1: length=1 position=0
23: length=2 position=2
456: length=3 position=5
  • prefix() — возвращает ссылку на объект sub_match, содержащий информацию о части строки перед фрагментом, соответствующим шаблону регулярного выражения. Прототип метода:
const_reference prefix() const;
typedef const value_type &const_reference;
typedef sub_match<_Bi_iter> value_type;
  • suffix() — возвращает ссылку на объект sub_match, содержащий информацию о части строки после фрагмента, соответствующего шаблону регулярного выражения. Прототип метода:
const_reference suffix() const;

Найдем и разберем на составные части адрес электронной почты, используя  класс smatch:

std::regex::flag_type flags =
            std::regex::icase | std::regex::ECMAScript;
std::regex rgx(
     "([a-z0-9_.-]+)@((?:[a-z0-9-]+\\.)+[a-z]{2,6})", flags);
std::string str("text1 <user@mail.ru> text2");
std::smatch m;
if (std::regex_search(str, m, rgx)) {
   std::cout << m.prefix() << std::endl; // text1 <
   std::cout << m.str(0) << std::endl;   // user@mail.ru
   std::cout << m.str(1) << std::endl;   // user
   std::cout << m.str(2) << std::endl;   // mail.ru
   std::cout << m.suffix() << std::endl; // > text2
}
  • format() — создает строку на основе строки формата format. Основные прототипы метода:
string_type format(const char_type *format,
                   match_flag_type flags=format_default) const;
template<typename _St, typename _Sa>
   basic_string<char_type, _St, _Sa>
   format(const basic_string<char_type, _St, _Sa> &format,
          match_flag_type flags=format_default) const;

В строке формата format можно указать следующие комбинации символов:

  • $& — фрагмент полностью совпадающий с шаблоном;
  • $n — фрагмент внутри группы с индексом n (нумерация групп внутри шаблона начинается с 1);
  • $` — часть строки перед фрагментом, соответствующим шаблону;
  • $' — часть строки после фрагмента, соответствующего шаблону;
  • $$ — символ $.

Пример:

std::regex::flag_type flags =
            std::regex::icase | std::regex::ECMAScript;
std::regex rgx(
     "([a-z0-9_.-]+)@((?:[a-z0-9-]+\\.)+[a-z]{2,6})", flags);
std::string str("text1 <user3@mail.ru> text2");
std::smatch m;
if (std::regex_search(str, m, rgx)) {
   std::cout << m.format("prefix: $`, E-mail: $&\nuser: $1, "
                         "site: $2, suffix: $'") << std::endl;
}

Результат:

prefix: text1 <, E-mail: user3@mail.ru
user: user3, site: mail.ru, suffix: > text2

Каждое совпадение описывается объектом шаблонного класса sub_match:

template<typename _BiIter>
   class sub_match : public pair<_BiIter, _BiIter>

Псевдонимы:

typedef sub_match<const char*> csub_match;
typedef sub_match<const wchar_t*> wcsub_match;
typedef sub_match<string::const_iterator> ssub_match;
typedef sub_match<wstring::const_iterator> wssub_match;

Основные методы класса sub_match:

  • str() — возвращает объект класса basic_string с содержимым совпадения. Прототип метода:
string_type str() const;
typedef basic_string<value_type> string_type;
  • length() — возвращает длину фрагмента. Прототип метода:
difference_type length() const;

Класс sub_match не хранит последовательность символов, он хранит лишь пару указателей или итераторов в виде структуры pair. Структура pair содержит два поля first и second, которые позволяют получить первое и второе значение из пары соответственно:

_T1 first;
_T2 second;

Пример:

std::regex rgx("([0-9]+) ([0-9]+)");
std::cmatch m;
if (std::regex_search("23 456", m, rgx)) {
   std::cout << m[1] << std::endl;          // 23
   std::cout << m[1].str() << std::endl;    // 23
   std::cout << m[1].length() << std::endl; // 2
   std::string s(m[1].first, m[1].second);
   std::cout << s << std::endl;             // 23
}

Учебник C++ (MinGW-W64)
Учебник C++ (MinGW-W64) в формате PDF

Помощь сайту

ЮMoney (Yandex-деньги): 410011140483022

ПАО Сбербанк:
Счет: 40817810855006152256
Реквизиты банка:
Наименование: СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК
Корреспондентский счет: 30101810500000000653
БИК: 044030653
КПП: 784243001
ОКПО: 09171401
ОКОНХ: 96130
Скриншот реквизитов