Проверка орфографии в приложениях Qt

от автора

В данной статье описано как добавить к вашему приложению на Qt проверку орфографии с подсветкой орфографически некорректных слов и возможность замены на более подходящие варианты. Для этого используется словарь hunspell.

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

Первым делом, поскольку мы работаем с библиотекой hunspell, необходимо её подключить. Для этого в .pro файл добавляем строку: LIBS += -lhunspell.

Далее создадим свои собственные классы унаследованные от QSyntaxHighlighter и QTextEdit.

Заголовочный файл classes.h:

#ifndef CLASSES_H #define CLASSES_H #include <QSyntaxHighlighter> #include <QTextEdit>   class SpellingHighlighter : public QSyntaxHighlighter // Класс для подсвечивания текста {     Q_OBJECT      public:     SpellingHighlighter(QTextEdit *parent) :QSyntaxHighlighter(parent) {}      protected:     virtual void highlightBlock(const QString &text) override; };  class BodyTextEdit : public QTextEdit // Класс для ввода и отображения текста {     Q_OBJECT      public:     BodyTextEdit(QWidget* parent = 0);           public slots:     void openCustomMenu(QPoint);     void correctWord(QAction * act);      protected:     SpellingHighlighter * m_highLighter; }; #endif // CLASSES_H

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

// correct - флаг корректно ли слово, getSuggests - получать ли варианты корректных слов QStringList suggestCorrections(const QString &word, bool &correct, bool getSuggests = false) {     static Hunspell * m_hunSpell = new Hunspell("/usr/share/hunspell/ru_RU.aff", "/usr/share/hunspell/ru_RU.dic");//данные пути корректны для debian     static QString  encoderStr = QString::fromLatin1( m_hunSpell->get_dic_encoding());// Могут быть различные кодеки, например KOI8-R      static QTextCodec * m_codec = QTextCodec::codecForName(encoderStr.toLatin1().constData());      correct = m_hunSpell->spell(m_codec->fromUnicode(word).constData()) != 0; // проверяем есть ли данное слово в словаре     if (getSuggests == false)         return QStringList();     QStringList suggestions;     char **suggestWordList = NULL;      try {         // Encode from Unicode to the encoding used by current dictionary         int count = m_hunSpell->suggest(&suggestWordList, m_codec->fromUnicode(word).constData());// получаем список возможных вариантов         QString lowerWord = word.toLower();          for (int i = 0; i < count; ++i) {             QString suggestion = m_codec->toUnicode(suggestWordList[i]);             suggestions << suggestion;             free(suggestWordList[i]);         }     }     catch(...)     {         qDebug() <<"Error keyword";     }     return suggestions; } 

Остается только определить классы и грамотно использовать данную функцию:

#include <QSyntaxHighlighter> #include <QCompleter> #include <QTextCodec> #include <QAction> #include <QTextEdit> #include <QMenu> #include "hunspell/hunspell.hxx" // from package libhunspell-dev #include <QDebug> #include "classes.h"  //Описанная чуть выше функция  QStringList suggestCorrections(const QString &word, bool &correct, bool getSuggests = false) {     static Hunspell * m_hunSpell = new Hunspell("/usr/share/hunspell/ru_RU.aff", "/usr/share/hunspell/ru_RU.dic");     static QString  encoderStr = QString::fromLatin1( m_hunSpell->get_dic_encoding());     static QTextCodec * m_codec = QTextCodec::codecForName(encoderStr.toLatin1().constData());      correct = m_hunSpell->spell(m_codec->fromUnicode(word).constData()) != 0;     if (getSuggests == false)         return QStringList();     QStringList suggestions;     char **suggestWordList = NULL;      try {         // Encode from Unicode to the encoding used by current dictionary         int count = m_hunSpell->suggest(&suggestWordList, m_codec->fromUnicode(word).constData());         QString lowerWord = word.toLower();          for (int i = 0; i < count; ++i) {             QString suggestion = m_codec->toUnicode(suggestWordList[i]);             suggestions << suggestion;             free(suggestWordList[i]);         }     }     catch(...)     {         qDebug() <<"Error keyword";     }     return suggestions; }  // Переопределяем функцию подсветки текста void SpellingHighlighter::highlightBlock(const QString &text) {     QStringList list = text.split(QRegExp("\\s+"), QString::KeepEmptyParts);//Регулярное выражения по поиску слов     QTextCharFormat spellingFormat;//Определяем как именно мы будем подсвечивать слова     spellingFormat.setUnderlineStyle(QTextCharFormat::SpellCheckUnderline);     spellingFormat.setUnderlineColor(Qt::red);     int count_word = list.size();     int pointer = 0;     for (int i= 0; i< count_word; i++)     {         bool correct = false;         QString sect = text.section(QRegExp("\\s+"), i, i, QString::SectionIncludeLeadingSep);         sect.remove(QRegExp("[,!?&*|]"));// Удаляем лишние символы         suggestCorrections(sect, correct);//Проверяем корректно ли слово         if (!correct)         {             setFormat(pointer, sect.length(),spellingFormat);         }         pointer += sect.length();     } };   BodyTextEdit::BodyTextEdit(QWidget* parent ) : QTextEdit(parent) {     this->setContextMenuPolicy(Qt::CustomContextMenu);     m_highLighter = new SpellingHighlighter(this);     connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(openCustomMenu(QPoint))); }  //Создание контекстного меню с предложенными вариантами замены void BodyTextEdit::openCustomMenu(QPoint pos) {     QMenu* popupmenu = this->createStandardContextMenu();     QTextCursor cursor = this->textCursor();     cursor.select(QTextCursor::WordUnderCursor);     this->setTextCursor(cursor);     if (this->textCursor().hasSelection())     {         QString text = this->textCursor().selectedText();         bool correct = false;         QStringList suggest = suggestCorrections(text, correct, true);         auto firstAction = popupmenu->actions().first();         if (!correct)         {             QList<QAction*> addedActions;             for (auto word  : suggest)             {                 QAction * act = new QAction(word, popupmenu);                 act->setData(word);                 addedActions.append(act);             }             popupmenu->insertActions(firstAction, addedActions);             connect(popupmenu, SIGNAL(triggered(QAction*)), this, SLOT(correctWord(QAction*)));         }     }     popupmenu->exec(this->mapToGlobal(pos));     delete popupmenu; }  //Замена слова на выбранное в меню void BodyTextEdit::correctWord(QAction *act) {     if (act->data().isNull())         return;     QString word = act->data().toString();     QTextCursor cursor = this->textCursor();     cursor.beginEditBlock();      cursor.removeSelectedText();     cursor.insertText(word);     cursor.endEditBlock(); } 

Заключение:

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

ссылка на оригинал статьи https://habr.com/ru/post/544650/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *