» » » » Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

На нашем литературном портале можно бесплатно читать книгу Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп, Бьёрн Страуструп . Жанр: Программирование. Онлайн библиотека дает возможность прочитать весь текст и даже без регистрации и СМС подтверждения на нашем литературном портале litmir.org.
Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп
Название: Программирование. Принципы и практика использования C++ Исправленное издание
Дата добавления: 22 август 2024
Количество просмотров: 98
Читать онлайн

Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних просмотр данного контента СТРОГО ЗАПРЕЩЕН! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту readbookfedya@gmail.com для удаления материала

Программирование. Принципы и практика использования C++ Исправленное издание читать книгу онлайн

Программирование. Принципы и практика использования C++ Исправленное издание - читать бесплатно онлайн , автор Бьёрн Страуструп

Специальное издание самой читаемой и содержащей наиболее достоверные сведения книги по C++. Книга написана Бьярне Страуструпом — автором языка программирования C++ — и является каноническим изложением возможностей этого языка.
Помимо подробного описания собственно языка, на страницах книги вы найдете доказавшие свою эффективность подходы к решению разнообразных задач проектирования и программирования. Многочисленные примеры демонстрируют как хороший стиль программирования на С-совместимом ядре C++, так и современный -ориентированный подход к созданию программных продуктов. Третье издание бестселлера было существенно переработано автором. Результатом этой переработки стала большая доступность книги для новичков. В то же время, текст обогатился сведениями и методиками программирования, которые могут оказаться полезными даже для многоопытных специалистов по C++. Не обойдены вниманием и нововведения языка: стандартная библиотека шаблонов (STL), пространства имен (namespaces), механизм идентификации типов во время выполнения (RTTI), явные приведения типов (cast-операторы) и другие.
Настоящее специальное издание отличается от третьего добавлением двух новых приложений (посвященных локализации и безопасной обработке исключений средствами стандартной библиотеки), довольно многочисленными уточнениями в остальном тексте, а также исправлением множества опечаток.
Книга адресована программистам, использующим в своей повседневной работе C++. Она также будет полезна преподавателям, студентам и всем, кто хочет ознакомиться с описанием языка «из первых рук».

Перейти на страницу:
символа: теперь символ ( является специальным, как и символы и {. Обычно символ | используется для обозначения операции “или” (альтернативы), а символ ? — для обозначения чего-то условного (необязательного). Итак, можем написать следующее:

(w{2}d{5})|(w{2}d{5}–d{4})

и

(w{2}d{5})(–d{4})?

Как и фигурные скобки при обозначении счетчиков (например, w{2}), знак вопроса (?) используется как суффикс. Например, (–d{4})? означает “необязательно –d{4}”; т.е. мы интерпретируем четыре цифры, перед которыми стоит дефис, как суффикс. На самом деле мы не используем круглые скобки для выделения пятизначного почтового кода ZIP (w{2}d{5}) для выполнения какой-либо операции, поэтому их можно удалить.

w{2}d{5}(–d{4})?

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

w{2} ?d{5}(–d{4})?

Запись “?” выглядит довольно странно, но знак вопроса после пробела указывает на то, что пробел является необязательным. Если бы мы хотели, чтобы пробел не выглядел опечаткой, то должны были бы заключить его в скобки.

w{2}( )?d{5}((–d{4})?

Если бы кто-то сказал, что эта запись выглядит слишком неразборчивой, то нам пришлось бы придумать обозначение для пробела, например s (s — от слова “space”). В этом случае запись выглядела бы так:

w{2}s?d{5}(–d{4})?

А что если кто-то поставит два пробела после букв? В соответствии с определенным выше шаблоном это означало бы, что мы принимаем коды TX77845 и TX 77845, но не TX 77845. Это неправильно.

Нам нужно средство, чтобы сказать “ни одного, один или несколько пробелов”, поэтому мы вводим суффикс *.

w{2}s*d{5}(–d{4})?

 

 Было бы целесообразно выполнять каждый этап в строгой логической последовательности. Эта система обозначения логична и очень лаконична. Кроме того, мы не принимали проектные решения с потолка: выбранная нами система обозначений очень широко распространена. При решении большинства задач, связанных с обработкой текста, нам необходимо читать и записывать эти символы. Да, эти записи похожи на результат прогулки кошки по клавиатуре, и ошибка в единственном месте (наш лишний или пропущенный пробел) полностью изменяет их смысл, но с этим приходится смириться. Мы не можем предложить ничего радикально лучшего, и этот стиль обозначений за тридцать лет распространился очень широко. Впервые он был использован в команде grep в системе Unix, но и даже тогда его нельзя было назвать совершенно новым.

23.7. Поиск с помощью регулярных выражений

Теперь применим шаблон почтовых кодов ZIP из предыдущего раздела для поиска почтовых кодов в файле. Программа определяет шаблон, а затем ищет его, считывая файл строка за строкой. Когда программа находит шаблон в какой-то строке, она выводит номер строки и найденный код.

#include <boost/regex.hpp>

#include <iostream>

#include <string>

#include <fstream>

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.hpp>

...

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.

Переменная matches имеет тип smatch. Буква s означает “sub.” По существу, тип smatch представляет собой вектор частичных совпадений. Первый элемент matches[0] представляет собой полное совпадение. Мы можем интерпретировать элемент matches[i] как строку, если i<matches.size(). Итак, если для данного регулярного выражения максимальное количество частичных шаблонов равно N, выполняется условие matches.size()==N+1.

 

 Что такое частичный шаблон (sub-pattern)? Можно просто сказать: “Все, что заключено в скобки внутри шаблона”. Глядя на шаблон "\w{2}\s*\d{5}(–\d{4})?", мы видим скобки вокруг четырехзначного кода ZIP. Таким образом, мы видим только один частичный шаблон, т.е. matches.size()==2. Кроме того, можно догадаться, что у нас есть простой доступ к этим четырем последним цифрам. Рассмотрим пример.

while (getline(in,line)) {

  boost::smatch matches;

  if (boost::regex_search(line, matches, pat)) {

    cout << lineno << ":

Перейти на страницу:
Комментариев (0)