Д. Стефенс - C++. Сборник рецептов
- Название:C++. Сборник рецептов
- Автор:
- Жанр:
- Издательство:КУДИЦ-ПРЕСС
- Год:2007
- Город:Москва
- ISBN:5-91136-030-6
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Д. Стефенс - C++. Сборник рецептов краткое содержание
Данная книга написана экспертами по C++ и содержит готовые рецепты решения каждодневных задач для программистов на С++. Один из авторов является создателем библиотеки Boost Iostreams и нескольких других библиотек C++ с открытым исходным кодом. В книге затрагивается множество тем, вот лишь некоторые из них: работа с датой и временем; потоковый ввод/вывод; обработка исключений; работа с классами и объектами; сборка приложений; синтаксический анализ XML-документов; программирование математических задач. Читатель сможет использовать готовые решения, а сэкономленное время и усилия направить на решение конкретных задач.
C++. Сборник рецептов - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
typedef map StrStrMap;
За более подробным описанием map обратитесь к рецепту 4.18. TextAutoField
хранит указатель на map
, так как, вероятнее всего, для всех полей потребуется только один общий словарь.
Предполагая, что клиентский код помещает в map
что-то осмысленное, append
просто должен периодически проверять trap
. В примере 4.31 append
ждет появления пробела или знака пунктуации. Для проверки на пробел можно использовать isspace
, а для поиска знаков пунктуации можно использовать ispunct. Обе эти функции для узких символов определены в (см. табл. 4.3).
Если вы не знакомы с использованием итераторов и методов поиска в контейнерах STL, то код, который выполняет проверку, требует некоторых пояснений, string tmp
содержит последний фрагмент текста, который был добавлен в TextAutoField
. Чтобы увидеть, был ли он написан с ошибками, поищите его в словаре вот так.
StrStrMap::iterator p = pDict->find(tmp);
if (p != pDict_->end()) {
Здесь важно то, что map::find
в случае успеха поиска возвращает итератор, который указывает на пару, содержащую соответствующий ключ. Если поиск не дал результатов, то возвращается итератор, указывающий на область памяти после последнего элемента map
, на который указывает map::end
(именно так работают контейнеры STL, поддерживающие find
). Если слово в map
найдено, стираем из буфера старое слово и заменяем его правильной версией.
buf_.erase(i, buf_.length() - i);
buf_ += p->second;
Добавьте символ, который инициировал весь процесс (либо пробел, либо знак пунктуации), и все.
Рецепты 4.17, 4.18 и табл. 4.3.
4.23. Чтение текстового файла с разделителями-запятыми
Требуется прочитать текстовый файл, чье содержимое разделено запятыми и новыми строками (или любой другой парой разделителей). Записи разделяются одним символом, а поля записи разделяются другим символом. Например, текстовый файл с разделителями-запятыми, содержащий информацию о сотрудниках, может выглядеть вот так.
Smith, Bill, 5/1/2002, Active
Stanford, John, 4/5/1999, Inactive
Такие файлы обычно временно хранят наборы данных, экспортируемые из электронных таблиц, баз данных или других форматов файлов.
Пример 4.32 демонстрирует, как это делается. Если читать текст в string
непрерывными кусками с помощью getline
(шаблон функции определен в ), то для анализа текста и создания структуры данных можно использовать функцию split
, которая была представлена в рецепте 4.6.
Пример 4.32. Чтение файла с разделителями
#include
#include
#include
#include
using namespace std;
void split(const string& s, char c, vector& v) {
int i = 0;
int j = s.find(c);
while (j >= 0) {
v.push_back(s.substr(i, j-i));
i = ++j;
j = s.find(c, j);
if (j < 0) {
v.push_back(s.substr(i, s.length()));
}
}
}
void loadCSV(istream& in, vector*>& data) {
vector* p = NULL;
string tmp;
while (!in.eof()) {
getline(in, tmp, '\n'); // Получить следующую строку
p = new vector();
split(tmp, '.', *p); // Использовать split из
// Рецепта 4.7
data.push_back(p);
cout << tmp << '\n';
tmp.clear();
}
}
int main(int argc, char** argv) {
if (argc < 2)
return(EXIT_FAILURE);
ifstream in(argv[1]);
if (!in)
return(EXIT_FAILURE);
vector*> data;
loadCSV(in, data);
// Выполнить с данными какие-либо действия...
for (vector*>::iterator p = data.begin();
p != data end(); ++p) {
delete *p; // Убедитесь, что p
} // разыменован!
}
В примере 4.32 почти нет ничего, что еще не было бы описано, getline
обсуждается в рецепте 4.19, a vector
— в рецепте 4.3. Единственный фрагмент, заслуживающий упоминания, — это выделение памяти.
loadCSV
создает новый vector
для каждой прочитанной строки данных и сохраняет его в другом vector, состоящем из указателей на vector
. Так как память для каждого из этих векторов выделяется из кучи, кто-то должен удалить ее, и этот кто-то — это вы (а не реализация vector
).
vector
ничего не знает о том, содержит ли он значение или указатель на значение или что-либо еще. Все, что он знает, — это то, что при его удалении он должен вызвать деструктор для каждого содержащегося в нем элемента. Если vector
хранит объекты, то все нормально, объект будет удален правильно. Но если vector
содержит указатели, то удалены будут указатели, а не объекты, на которые они указывают.
Есть два способа гарантировать освобождение памяти. Первый заключается в том, что сделано в примере 4.32 вручную, как здесь.
for (vector*>::iterator p = data.begin();
p != data.end(); ++p) {
delete *p;
}
Либо можно использовать указатель со счетчиком ссылок, такой как smart_ptr
из проекта Boost, который станет частью будущего стандарта C++0x. Но реализация этого нетривиальна, так что я рекомендую почитать, что такое smart_ptr
и как он работает. Для получения дополнительной информации по Boost посетите его домашнюю страницу по адресу www.boost.org .
4.24. Использование регулярных выражений для разделения строки
Требуется разделить строку на лексемы, но необходимо выполнить более сложный поиск, чем показано в рецепте 4.7. Например, могут потребоваться лексемы, разделенные более чем одним символом или имеющие несколько различных форм. Это часто приводит к большому коду и путанице среди пользователей вашего класса или функции.
Используйте шаблон класса regex
Boost. regex
позволяет использовать для строк и текстовых данных регулярные выражения. Пример 4.33 показывает, как использовать regex
для разделения строк.
Пример 4.33. Использование регулярных выражений Boost
#include
#include
#include
int main() {
std::string s = "who,lives-in-a,pineapple under the sea?";
boost::regex re(',|:|-|\\s+"); // Создаем регулярное выражение
boost::sregex_token_iterator // Создаем итератор, используя
p(s.begin(), s.end(), re, -1), // последовательность и это выражение
boost::sregex_token_iterator end; // Создаем маркер
// «конец-рег-выражения»
while (p != end)
std::cout << *p++ << '\n';
}
Пример 4.33 показывает, как использовать regex
для перебора соответствий регулярному выражению. Следующая строка создает регулярное выражение.
boost::regex re(' ,|:| -|\\s+");
Она гласит, что каждое соответствие регулярному выражению — это либо запятая, либо двоеточие, либо тире, либо один или несколько пробелов. Символ канала — это логический оператор OR, используемый для объединения разделителей. Следующие две строки создают итератор.
Читать дальшеИнтервал:
Закладка: