grep
в системе Unix, но и даже тогда его нельзя было назвать совершенно новым.
23.7. Поиск с помощью регулярных выражений
Теперь применим шаблон почтовых кодов ZIP из предыдущего раздела для поиска почтовых кодов в файле. Программа определяет шаблон, а затем ищет его, считывая файл строка за строкой. Когда программа находит шаблон в какой-то строке, она выводит номер строки и найденный код.
#include
#include
#include
#include
using namespace std;
int main()
{
ifstream in("file.txt"); // файл ввода
if (!in) cerr << "нет файла \n";
boost::regex pat ("\\w{2}\\s*\\d{5}(–\\d{4})?"); // шаблон
// кода ZIP
cout << "шаблон: " << pat << '\n';
int lineno = 0;
string line; // буфер ввода
while (getline(in,line)) {
++lineno;
boost::smatch matches; // записываем сюда совпавшие строки
if (boost::regex_search(line, matches, pat))
cout << lineno << ": " << matches[0] << '\n';
}
}
Эта программа требует объяснений. Сначала рассмотрим следующий фрагмент:
#include
...
boost::regex pat ("\\w{2}\\s*\\d{5}(–\\d{4})?"); // шаблон кода ZIP
boost::smatch matches; // записываем сюда совпавшие строки
if (boost::regex_search(line, matches, pat))
Мы используем реализацию библиотеки Boost.Regex
, которая скоро станет частью стандартной библиотеки. Для того чтобы использовать библиотеку Boost.Regex
, ее необходимо инсталлировать. Для того чтобы показать, какие возможности относятся к библиотеке Boost.Regex
, мы явно указываем пространство имен boost
в качестве квалификатора, т.е. boost::regex
.
Вернемся к регулярным выражениям! Рассмотрим следующий фрагмент кода:
boost::regex pat ("\\w{2}\\s*\\d{5}(–\\d{4})?");
cout << "шаблон: " << pat << '\n';
Здесь мы сначала определили шаблон pat
(типа regex
), а затем вывели его на печать. Обратите внимание на то, что мы написали:
\\w{2}\\s*\\d{5}(–\\d{4})?
Если бы вы запустили программу, то увидели бы на экране следующую строку:
pattern: \w{2}\s*\d{5}(–\d{4})?
В строковых литералах языка С++ обратная косая черта означает управляющий символ (раздел A.2.4), поэтому вместо одной обратной косой черты (\) в литеральной строке необходимо написать две (\\).
regex
на самом деле является разновидностью объекта класса string
, поэтому мы можем вывести его на печать с помощью оператора <<
. Класс regex
— это не string
, но его довольно сложный механизм сопоставления шаблонов, созданных при инициализации объекта класса regex
(или при выполнении оператора присваивания), выходит за рамки рассмотрения нашей книги. Однако, поскольку мы инициализировали объект класса regex
шаблоном почтовых кодов, можем применить его к каждой строке нашего файла.
boost::smatch matches;
if (boost::regex_search(line, matches, pat))
cout << lineno << ": " << matches[0] << '\n';
regex_search(line, matches, pat)
ищет в строке line
любое соответствие регулярному выражению, хранящемуся в объекте pat
, и если она находит какое-либо соответствие, то сохраняет его в объекте matches
. Естественно, если соответствие не обнаружено, функция regex_search(line, matches, pat)
возвращает значение false
.