Имеется класс, который представляет некий тип текстового поля или документа, и по мере добавления в него текста требуется автоматически корректировать неправильно написанные слова, как это делает функция Autocorrect (Автозамена) в Microsoft Word.

Решение

Это можно реализовать в относительно небольшом коде, если использовать map, который определен в , string и различные возможности стандартной библиотеки. Пример 4.31 показывает, как это делается.

Пример 4.31. Автозамена текста

#include

#include

#include

#include

using namespace std;

typedef map StrStrMap;

// Класс для хранения текстовых полей

class TextAutoField {

public:

 TextAutoField(StrStrMap* const p) : pDict_(p) {}

 ~TextAutoField() {}

 void append(char c);

 void getText(string& s) {s = buf_;}

private:

 TextAutoField();

 string buf_;

 StrStrMap* const pDict ;

};

// Добавление с автозаменой

void TextAutoField::append(char c) {

 if ((isspace(c) || ispunct(c)) &&     // Выполнять автоза-

  buf_.length() > 0 &&                 // мену, только когда вводятся

  !isspace(buf_[buf_.length() - 1])) { // ws или punct

  string::size_type i = buf_.find_last_of(" \f\n\r\t\v");

  i = (i == string::npos) ? 0 : ++i;

  string tmp = buf_.substr(i, buf_.length() - i);

  StrStrMap::const_iterator p = DDict_->find(tmp);

  if (p != pDict_->end()) {          // Нашли, так что стираем

   buf_.erase(i, buf_.length() - i); // и заменяем

   buf_ += p->second;

  }

 }

 buf_ += с;

}

int main() {

 // Создаем map

 StrStrMap dict;

 TextAutoField txt(&dict);

 dict["taht"] = "that";

 dict["right"] = "wrong";

 dict["bug"] = "feature";

 string tmp = "He's right, taht's a bug.";

 cout << "Оригинальная версия: " << tmp << '\n';

 for (string::iterator p = tmp.begin(); p != tmp.end(); ++p) {

  txt.append(*p);

 }

 txt.getText(tmp);

 cout << "Исправленная версия. " << tmp << '\n';

}

Вывод примера 3.2 таков.

Оригинальная версия: He's right, taht's a bug.

Исправленная версия: He's wrong, that's a feature.

Обсуждение

string и map удобны в ситуациях, когда требуется отслеживать ассоциации string. TextAutoField — это простой текстовый буфер, использующий string для хранения данных. Интересной TextAutoField делает ее метод append, который «слушает» пробелы или знаки пунктуации и при их появлении выполняет обработку.

Чтобы сделать автозамену работающей, требуется две вещи. Во-первых, требуется некий словарь, который содержит неправильно написанные варианты слов и связанные с ними правильные написания, map хранит пары ключ/значение, где ключ и значение могут быть любого типа, так что он является идеальным кандидатом на эту роль. В начале примера 4.31 имеется typedef для пар string:

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);

Перейти на страницу:

Похожие книги