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.
#include
#include
#include
#include
using namespace std;
void split(const string& s, char c, vector
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
vector
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
loadCSV(in, data);
// Выполнить с данными какие-либо действия...
for (vector
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
p != data.end(); ++p) {
delete *p;
}