Difference between revisions of "spelling/ru"

From Free Pascal wiki
Jump to navigationJump to search
 
(31 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{LanguageBar|spelling}}
+
{{spelling}}
  
  
Line 7: Line 7:
 
= Использование hunspell с Lazarus =
 
= Использование hunspell с Lazarus =
  
'''Эта страница актуальна по состоянию на август 2018 года, но все меняется .....'''
+
{{Note|Эта страница актуальна по состоянию на август 2018 года, но все меняется .....}}
  
 
Эта страница посвящена использованию библиотеки hunspell с Lazarus. Он описывает модель, которая работает, вроде как. Вам почти наверняка понадобится внести некоторые изменения для ваших конкретных целей, но, надеюсь, эта страница послужит вам хорошим началом.
 
Эта страница посвящена использованию библиотеки hunspell с Lazarus. Он описывает модель, которая работает, вроде как. Вам почти наверняка понадобится внести некоторые изменения для ваших конкретных целей, но, надеюсь, эта страница послужит вам хорошим началом.
Line 13: Line 13:
 
Во-первых, на форуме есть несколько ссылок на некоторый код, который будет работать с библиотекой hunspell. Модуль hunspell.pas в значительной степени основан на этих блоках кода. У большинства нет информации о лицензии, и делается предположение, что она является «общеизвестной» и, следовательно, свободна от каких-либо ограничений. Я добавил немного, что решает проблему поиска файлов библиотеки и словаря. И установил разумный интерфейс.
 
Во-первых, на форуме есть несколько ссылок на некоторый код, который будет работать с библиотекой hunspell. Модуль hunspell.pas в значительной степени основан на этих блоках кода. У большинства нет информации о лицензии, и делается предположение, что она является «общеизвестной» и, следовательно, свободна от каких-либо ограничений. Я добавил немного, что решает проблему поиска файлов библиотеки и словаря. И установил разумный интерфейс.
  
Кроме того, пользователь rvk с форума создал Windows 64-битную DLL, так как для пользователей Windows не было никакой альтернативы.
+
Кроме того, пользователь [[https://forum.lazarus.freepascal.org/index.php?action=profile;u=55059 rvk]] с форума создал Windows 64-битную DLL, так как для пользователей Windows не было никакой альтернативы.
  
 +
= О библиотеке Hunspell =
  
== About Hunspell ==
+
Hunspell - это активный проект с открытым исходным кодом, распространяемый по открытой лицензии Mozilla. Библиотека hunspell используется в таких продуктах, как Libra Office, Open Office и Firefox. Его можно заставить работать на Windows, Linux и Mac (и, возможно, на кучах других платформ). См. ссылки на платформоспецифичные страницы ниже. Словари Hunspell легко доступны и, возможно, уже установлены на многих машинах. Даже если вы не можете получить доступ к библиотеке другого приложения, вы можете использовать его словарь.
  
Hunspell is an active open source project, distributed under the Mozilla Public License. The hunspell library is used in products like Libra Office, Open Office and Firefox. Its can be made work on Windows, Linux and Mac (and probably heaps of other platforms). See the platform Specific pages below. Dictionaries for Hunspell are readily available and may already be installed on many machines. Even if you cannot access another application's library, you can use its dictionary.
+
Словари Hunspell поставляются в виде пары файлов *.dic и *.aff. Например, австралийский словарь состоит из en_AU.dic и en_AU.aff. Префикс 'en' обозначает его английский, а суффикс 'AU' говорит о его специфичности специально для Австралии. Как говорящий по-английски, я отмечаю, что словари en_US, кажется, всегда установлены, и я добавляю австралийские. Я не знаю, насколько распространен этот шаблон в не-англоязычных системах.
  
Dictionaries for Hunspell come as a *.dic and *.aff file pair.  For example, the Australian dictionary consists of en_AU.dic and en_AU.aff . The 'en' indicates its english and the 'AU' says its specifically for Australia. As an English speaker, I note that the en_US dictionaries always seem to be installed and I add the Australian ones. I don't know how widespread this pattern is in non English speaking systems.
+
Словари можно найти здесь https://github.com/LibreOffice/dictionaries, а также некоторую информацию, связанную с этим, здесь https://wiki.documentfoundation.org/Development/Dictionaries
  
== Platform Specific ==
+
= Замечание насчет словарей =
  
 +
В некоторых случаях для корректного отображения предлагаемых слов словари должны быть закодированы в UTF-8. Если вы заметили, что некоторые слова отображаются неправильно — например, яблоко на польском — это jabłko, а вы получаете jab�ko, — это означает, что словари pl_PL.aff и pl_PL.dic должны быть преобразованы в UTF-8. Чтобы преобразовать словари в UTF-8 в Linux Debian (это должно работать в любом Linux, конвертированные словари можно использовать в Windows - проверьте также [http://forum.lazarus.freepascal.org/index.php/topic,44298.0.html эту ветку форума]) выполните следующие действия:
  
=== Linux ===
+
1. Запустить терминал как root
Many Linux distributions will have Hunspell installed by default along with the appropriate language dictionaries. If not, its probably just a case of using the distribution's package manager. If all else fails, grab the source from the hunspell github site and build it yourself. Linux users are like that.
 
  
To see if you do in fact have a hunspell library installed, try this command - <code>ldconfig -p | grep hunspell</code>.  Similarly, you can probably find some dictionaries with <code>ls -l /usr/share/hunspell</code>.  If that does not work, try <code>find /usr -name *.aff</code>, it will take a bit longer ..
+
  su
  
=== Windows ===
+
2. Если он еще не установлен, установите hunspell (hunspell-pl для польского словаря — подробнее на [https://packages.debian.org/search?keywords=hunspell Debian Hunspell package])
Installing the hunspell library on windows is more of an issue. There is apparently no pre compiled 'kit' available and most Windows apps that use Hunspell appear to bind it staticly thus no hunspell.dll left lying around for you to use. But just to be sure, try searching for <code>*hunspell*.dll</code>. The Hunspell github site lists a recipe to build one but it involves installing MSYS2 and is quite involved. The resulting DLL also needs a couple of gcc DLLs along as well.
 
  
Fortunately user rvk on the Lazarus Forum has built us a nice statically (ie stand alone) linked DLL using  Microsoft Visual Studio Community 2015. As such, you can use and distribute this DLL with your programme subject to the Mozilla Public License.
+
  apt-get install hunspell
 +
  apt-get install hunspell-pl
  
You will find this DLL bundled with the 64bit (pre) release of tomboy-ng, just download the zip file, unzip and discard (how sad) the tomboy-ng binary. See https://github.com/tomboy-notes/tomboy-ng/releases
+
3. Перейдите в /usr/share/hunspell/, где хранятся словари, и создайте папку dic
  
=== Mac ===
+
  cd /usr/share/hunspell/
The author's Mac appears to have had the Hunspell library installed when Sierra was installed. But maybe, just maybe, it came along with Firefox. I'd like some feed back ....
+
  mkdir dic
  
To see if you aleady have a hunspell library installed, try this command - <code>find / 2>&1 | grep "\hunspell"</code>, it will run for some time, depending on how many files on your system. It will likely find several files including some in your XCode directory. However, end users will probably not have XCode installed. The one particularly interesting file to me was <code>/usr/lib/libhunspell-1.2.dylib</code>. Version 1.2 is a bit older than elsewhere but it worked fine.
+
4. Преобразуйте, например, словарь pl_PL.aff и pl_PL.dic.
 +
Используйте [https://en.wikipedia.org/wiki/ISO/IEC_8859-2 ISO-8859-2] (для Восточной Европы), [https://en.wikipedia.org/wiki/ISO/IEC_8859-1 ISO-8859-1] (или ISO-8859-15) для Западной Европы, [https://ru.wikipedia.org/wiki/ISO_8859-5 ISO-8859-5] для кириллицы и т.д.
  
If you don't find a usable library, I suggest you install one using brew, see link below.
+
  iconv -f ISO-8859-2 -t UTF-8 /usr/share/hunspell/pl_PL.aff | sed 's/^SET ISO8859-2$/SET UTF-8/g' > dic/pl_PL.aff
 +
  iconv -f ISO-8859-2 -t UTF-8 /usr/share/hunspell/pl_PL.dic > dic/pl_PL.dic
  
Next issue issue is you will need some dictionaries. Similar command, <code>find / 2>&1 | grep "\.aff"</code>, again, slow, it searches your whole disk. I found <code>/Applications/Firefox.app/Contents/Resources/dictionaries/en-US.aff</code>. And a quick 'ls' assured me that there was a matching 'en-US.dic' files so all good.
+
5. Скопируйте папку dic или словари из папки dic в свое приложение.
  
A more experienced Mac user might like to suggest better search strategies. Please !
+
= Платформозависимость =
  
== The Hunspell Unit ==
 
  
 +
== Linux ==
 +
Во многих дистрибутивах Linux по умолчанию установлен Hunspell вместе с соответствующими языковыми словарями. Если нет, то, вероятно, это просто случай использования менеджера пакетов дистрибутива. Если ничего не помогает, возьмите исходник с сайта hunspell github и создайте его самостоятельно. Пользователи Linux любят это.
  
=== Demo 1 simple command line ===
+
Чтобы проверить, установлена ли у вас библиотека hunspell, попробуйте эту команду
  
Here is a very simple command line demo of how to use hunspell.pas. Sadly, this particular demo is only suitable for linux as explained below. Save this block of code as testhun.pas and save hunspell.pas (below) in a directory and give this command :
+
  ldconfig -p | grep hunspell  
  
<code>fpc -Fu/usr/share/lazarus/1.8.0/components/lazutils/lib/x86_64-linux -Fu. testhun.pas</code>
+
Точно так же вы можете найти некоторые словари с помощью
  
If you are using 32bit linux or your lazarus is installed "somewhere else" you will need to adjust the parameter to -Fu
+
  ls -l /usr/share/hunspell
+
 
<syntaxhighlight>
+
Если это не сработает, попробуйте
program testhun;
+
 
 +
  find /usr -name *.aff
 +
 
 +
это займет немного больше времени.
 +
 
 +
== Windows ==
 +
Установка библиотеки hunspell на Windows является более серьезной проблемой. По-видимому, нет предварительно скомпилированного 'комплекта', и большинство приложений Windows, которые используют Hunspell, похоже, статически связывают его, поэтому не осталось никаких hunspell.dll для использования. Но просто, чтобы быть уверенным, попробуйте поискать <code>*hunspell*.dll</code>. На сайте Hunspell github приведен рецепт его создания, но он включает установку MSYS2 и довольно сложен. Получающаяся DLL также нуждается вдобавок в паре gcc DLL.
 +
 
 +
К счастью, пользователь [[user:rvk|rvk]] с форума Lazarus создал нам хорошую статически (т.е. автономно) связанную DLL-библиотеку с использованием Microsoft Visual Studio Community 2015. Таким образом, вы можете использовать и распространять эту DLL-библиотеку вместе с вашей программой, подпадающей под действие публичной лицензии Mozilla.
 +
 
 +
Вы найдете эту DLL в комплекте с файлом лицензии на https://github.com/davidbannon/hunspell4pas, щелкните «DLL», щелкните по файлу dll, и вы увидите кнопку «Загрузить». Не забудьте также получить файл лицензии, он должен распространяться, так или иначе, с вашим приложением.
 +
 
 +
 
 +
----
 +
 
 +
[[User:Zoltanleo|Прим.перев.]]: Вы также можете посмотреть исходники интерфейса Hunspell для Lazarus здесь: [https://github.com/cutec-chris/hunspell https://github.com/cutec-chris/hunspell]
 +
 
 +
----
 +
 
 +
== Mac ==
 +
 
 +
На Mac'е автора, по-видимому, была установлена библиотека Hunspell при установке Sierra. Но, может быть, просто возможно, это пришло вместе с Firefox. Я хотел бы получить обратную связь .... [уже установлено на Mojave и Catalina]
 +
 
 +
{{Note|См https://opensource.apple.com/tarballs/hunspell/ для загрузки исходников v1.2.8.}}
 +
 
 +
Чтобы проверить, установлена ли у вас библиотека hunspell, попробуйте эту команду
 +
 
 +
  find / 2>&1 | grep "\hunspell"
 +
 
 +
она будет выполняться некоторое время, в зависимости от того, сколько файлов в вашей системе. Скорее всего, она найдет несколько файлов, включая некоторые, в вашем каталоге XCode. Однако конечным пользователям, вероятно, не будет установлен XCode. Один особенно интересный файл для меня был
 +
 
 +
  /usr/lib/libhunspell-1.2.dylib
 +
 
 +
Версия 1.2 немного старше, чем где-либо, но работала нормально. Если вы не можете найти пригодную для использования библиотеку, я предлагаю вам установить его с помощью менеджера пакетов, такого как MacPorts, Fink или brew. Следующая проблема заключается в том, что вам понадобятся словари. Аналогичная команда
 +
 
 +
  find / 2>&1 | grep "\.aff"
 +
 
 +
опять же, медленная, она ищет по всему вашему диску. Я нашел команду
 +
 
 +
  /Applications/Firefox.app/Contents/Resources/dictionaries/en-US.aff
 +
 
 +
 
 +
И быстрый 'ls' заверил меня, что есть соответствующие файлы en-US.dic, так что все хорошо.
 +
 
 +
Более опытный пользователь Mac может предложить лучшие стратегии поиска. Пожалуйста!
  
{$mode objfpc}{$H+}
+
= Модуль Hunspell =
  
uses
+
При первоначальном создании этой страницы (2017?) я допустил серьезную ошибку и использовал код, у которого не было четкой лицензии или истории. Было высказано предположение, что тем самым я нарушил лицензию Hunspell, как и все, кто использовал ее с тех пор.
    Classes, hunspell, sysutils;
 
  
var
+
Чтобы исправить эту ситуацию, я выпустил новую версию Hunspell Wrapper, которая имеет довольно небольшую часть, только определения функций, с Hunspell (Лицензия: MPL 1.1/GPL 2.0/LGPL 2.1) и Hunspell Unit (Лицензия: Clear BSD License) в отдельных файлах. С точки зрения кодирования это почти идентично тому, что было здесь раньше.
  Spell : THunspell;
 
  Sts : TStringList;
 
  I : integer;
 
  
begin
+
См. https://github.com/davidbannon/hunspell4pas
    Spell := THunspell.Create();
 
    if Spell.ErrorMessage = '' then begin
 
      if Spell.SetDictionary('/usr/share/hunspell/en_US.dic') then begin
 
            writeln('speller ' + booltostr(Spell.Spell('speller'), True));
 
            writeln('badspeller ' + booltostr(Spell.Spell('badspeller'), True));
 
            Sts := TStringList.Create();
 
            Spell.Suggest('badspeller', Sts);
 
            for i := 0 to Sts.Count -1 do
 
                writeln('    ' + Sts.Strings[I]);
 
            Sts.Free;
 
      end else
 
        writeln('ERROR - Dictionary not loaded.');
 
    end else writeln('ERROR - Library not loaded.');
 
    Spell.Free;
 
end.
 
</syntaxhighlight>
 
  
Why is this particular demo Linux only ?  The hunspell unit is designed for GUI apps, it uses a Unit called Forms that don't make sense in a command line app. On Windows and Mac, a Forms method, Application.ExeName is used to determine where the binary is in case you have put the hunspell Library there (on Linux it has a predefined place to live).  
+
Я удалил оболочку hunspell, которая раньше находилась на этой странице. Тот, что на Github выше, является заменой, вам нужны hunspell.pas и hunspell.inc. Оставшаяся часть файла представляет собой базовый test/demo проект Lazarus командной строки, который заменяет Demo 1.
  
=== Demo 2 in a Full GUI ===
+
== Demo 2 в полном графическом интерфейсе ==
  
A Lazarus GUI demo makes a lot more sense and has been tested on Linux, Mac and Windows. But it is a bit harder to copy and paste.
+
Демо графического интерфейса Lazarus имеет больше смысла и была протестирована на Linux, Mac и Windows. Но это немного сложнее, [чем] скопировать и вставить.
  
For this demo, you'll need a form with two TMemos, Memo1 and MemoMsg. A button, ButtonSpell, a Tlistbox, Listbox1. Make the following event handlers : FormCreate for the main form; a double click for the listbox and click on the Button.
+
Для этой демо вам понадобится форма с двумя TMemo: Memo1 и MemoMsg. Кнопка ButtonSpell, Tlistbox Listbox1. Сделайте следующие обработчики событий: FormCreate для главной формы; дважды щелкните по Listbox1 и [дважды] кликните по ButtonSpell.
 
   
 
   
First you must create the hunspell object and see if it found a library its own way, here is an example in the FormCreate() method ....
+
Сначала вы должны создать объект hunspell и посмотреть, нашел ли он свою библиотеку, вот пример метода FormCreate () ....
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
uses hunspell;
 
uses hunspell;
 
var
 
var
Line 118: Line 146:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
In this example, we are writing some status message to MemoMsg, its an easy way to see whats happening. The ButtonSpell is NOT enabled  until the dictionaries have been set. Wait for it ....
+
В этом примере мы пишем сообщение о статусе в MemoMsg, это простой способ увидеть, что происходит. ButtonSpell НЕ включен, пока не будут установлены словари. Ожидаем этого ....
  
We now need two methods, one reads a nominated directory looking for any likely dictionary files, the other manages the decisions. If we find just one dictionary set, use it, if we find none, complain. But if we find several, and thats most likely, we have to ask the user which dictionary (ie language) they wish to use.
+
Теперь нам нужны два метода: один читает назначенный каталог и ищет возможные файлы словарей, другой управляет решениями. Если мы найдем только один словарный набор, используем его, если мы не найдем - пожалуемся. Но если мы найдем несколько, и это наиболее вероятно, мы должны спросить пользователя, какой словарь (то есть язык) он хочет использовать.
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
function TForm1.FindDictionary(const Dict : TStrings; const DPath : AnsiString) : boolean;
 
function TForm1.FindDictionary(const Dict : TStrings; const DPath : AnsiString) : boolean;
 
var
 
var
Line 142: Line 170:
 
     EditDictPath.Caption := DictPathAlt;
 
     EditDictPath.Caption := DictPathAlt;
 
     if not FindDictionary(ListBox1.Items, DictPath) then
 
     if not FindDictionary(ListBox1.Items, DictPath) then
         MemoMsg.Append('ERROR - no dictionaries found in ' + DictPath);
+
         MemoMsg.Append('ERROR - no dictionaries found in ' + DictPath);//[прим.перев.]: словари в DictPath не найдены
     if ListBox1.Items.Count = 1 then begin                  // Exactly one returned.
+
     if ListBox1.Items.Count = 1 then begin                  // Один [словарь] вернулся точно.
 
         if not Sp.SetDictionary(AppendPathDelim(DictPath) + ListBox1.Items.Strings[0]) then
 
         if not Sp.SetDictionary(AppendPathDelim(DictPath) + ListBox1.Items.Strings[0]) then
 
             MemoMsg.Append('ERROR ' + SP.ErrorMessage)
 
             MemoMsg.Append('ERROR ' + SP.ErrorMessage)
 
         else
 
         else
             MemoMsg.Append('Dictionary set to ' + DictPath + ListBox1.Items.Strings[0]);
+
             MemoMsg.Append('Dictionary set to ' + DictPath + ListBox1.Items.Strings[0]);// [прим.перев.]: словарь (первый из списка ListBox1) установлен в DictPath
 
     end;
 
     end;
     Result := SP.GoodToGo;  // only true if count was exactly one or FindDict failed and nothing changed
+
     Result := SP.GoodToGo;  // если count был точно один или FindDict не вернул ничего и ничего не изменилось
 
end;  
 
end;  
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Ah, you say, but where are we looking for the dictionaries ? Sadly, I don't have a good solution for that. Here is where I found mine -
+
Ах, вы спросите, но где нам искать словари? К сожалению, у меня нет хорошего решения для этого. Вот где я нашел свой -
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
procedure TForm1.SetDefaultDicPath();
 
procedure TForm1.SetDefaultDicPath();
 
begin
 
begin
Line 171: Line 199:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Maybe, if other users contribute where they found usable hunspell dictionaries, we can build a list for each platform. Or just take the easy way out and tell user to get some dictionaries and put them into the application directory on Windows and Mac. Your thoughts very welcome....
+
Возможно, если другие пользователи сообщат, где они нашли пригодные для использования словари Hunspell, мы можем составить список для каждой платформы. Или просто выберите легкий путь и попросите пользователя найти несколько словарей и поместить их в каталог приложений на Windows и Mac. Ваши мысли очень приветствуются ....
  
So far, if there is exactly one dictionary set in the indicated directory, all good. But what if there are several ? Our list box has a list of them, if the user double clicks one, they trigger this method -
+
Пока, если в указанном каталоге есть ровно один словарь, все хорошо. Но что, если их несколько? Наш ListBox1 содержит их список, если пользователь дважды щелкнет один из них, он вызовет этот метод -
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
procedure TForm1.ListBox1DblClick(Sender: TObject);
 
procedure TForm1.ListBox1DblClick(Sender: TObject);
 
begin
 
begin
Line 188: Line 216:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Assuming we now have everything "good to go" we can press the Spell button and trigger this -
+
Предполагая, что у нас теперь есть все, что нужно, мы можем нажать кнопку ButtonSpell и вызвать это -
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
procedure TForm1.ButtonSpellClick(Sender: TObject);
 
procedure TForm1.ButtonSpellClick(Sender: TObject);
 
begin
 
begin
Line 202: Line 230:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Memo1 now contains some suggestions for better ways to spell badspeller !
+
Memo1 теперь содержит несколько советов о лучших способах написания [слова] неграмотному!
  
Important ! Don't forget to free up our hunspeller object, memory leaks are evil !
+
Важно! Не забудьте освободить наш объект hunspeller, утечки памяти - зло!
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
procedure TForm1.FormDestroy(Sender: TObject);
 
procedure TForm1.FormDestroy(Sender: TObject);
 
begin
 
begin
Line 213: Line 241:
 
</syntaxhighlight>       
 
</syntaxhighlight>       
  
This module will do considerably more but its presented here in its most stripped down form for readability.
+
Этот модуль делает значительно больше, но он представлен здесь в его наиболее урезанной форме для удобства чтения.
 +
 
 +
{{Note| для новичков в Lazarus, методы с "(Sender: TObject)", показанные выше, не могут быть просто вставлены в ваш исходник, сначала используйте инспектор объектов формы, чтобы создать события, а затем вставьте мой пример кода в метод.}}
 +
 
 +
==Demo 3 - Lazspell - Tmemo==
 +
 
 +
В этом примере использовался компонент TMemo.
 +
 
 +
[[image:lazspell.gif]]
 +
 
 +
Lazspell -  пример проверки орфографии - из https://github.com/Raf20076/Lazspell
 +
 
 +
==Demo 4 - Lazspell 2-version 2 - TRichMemo ==
 +
 
 +
В этом примере использовался компонент TRichMemo.
 +
 
 +
[[image:lazspell-ver2.gif]]
 +
 
 +
Lazspell 2 v2 - пример проверки орфографии - изm https://github.com/Raf20076/Lazspell-2-version-2
 +
 
 +
==Demo 5 - Простая проверка орфографии ==
 +
 
 +
1. Запустите  IDE Lazarus
 +
 
 +
2. Кликните Project -> New Project -> Choose -> Application. Вы только что создали новое приложение. Теперь сохраните его
 +
 
 +
3. Кликните File -> Save as. Выберите папку, в которой будет сохранено ваше приложение. Сначала будет сохранен project1.lpi, затем unit1.pasunit1.pas
 +
 
 +
4. Поместите hunspell.pas и hunspell.inc (from  https://github.com/davidbannon/hunspell4pas) в вашу папку
 +
 
 +
5. Поместите libhunspell.dll в папку с вашим приложением (вы должны загрузить ее отсюда https://github.com/Raf20076/Lazspell или https://github.com/davidbannon/hunspell4pas) в любом случае или соберите ее самостоятельно.
 +
 
 +
6. Поместите словарь в папку приложения (оба файла), например pl_PL.aff, pl_PL.dic. Словари должны быть закодированы в UTF8. Скачать их можно отсюда https://github.com/Raf20076/Lazspell/tree/master/dict
 +
 
 +
7. Положите на Form1 компонент TButton (Button1) с вкладки Standard
 +
 
 +
8. Положите на Form1 компонен TMemo (Memo1) с вкладки Standard
 +
 
 +
9. Положите на Form1 компонен TListbox (ListBox1) с вкладки Standard (здесь будут отображаться слова с ошибками)
 +
 
 +
10. Кликните по кнопке Button1 на Form1 затем перейдите в ObjectInspector, щелкните по вкладке Events, затем дважды щелкните рядом с событием OnClik: это создаст событие OnClick, и код вставки (см. код всего приложения), начинающийся с
 +
 
 +
<syntaxhighlight lang=pascal> 
 +
{Check spelling}
 +
var
 +
    i : Integer;
 +
    MAX : Integer;
 +
    FillInArrayWithWords:TStringArray;
 +
    FillInString1: String;
 +
    FillInString2: String;
 +
</syntaxhighlight>
 +
 
 +
до
  
''A note to people new to Lazarus, methods with "(Sender: TObject)" shown above cannot just be pasted into your source, use the Form's Object Inspector to create the events first, then paste my sample code into the method.''
+
<syntaxhighlight lang=pascal>
  
=== Actual Code ===
+
//Если слова нет в словаре, показать его в Listbox как ошибку
 +
</syntaxhighlight>
  
 +
11. Перейдите в ObjectInspector и щелкните Form1, затем щелкните вкладку Events, затем дважды щелкните рядом с OnCreate, это создаст событие OnCreate и вставит код (см. код всего приложения)
  
(sorry, it really is too long to paste into and out of a wiki page but that seems my only option)
+
<syntaxhighlight lang=pascal>
 +
  SpellCheck := THunspell.Create(True);
 +
  SpellCheck.SetDictionary('pl_PL.dic');//загружаем словарь
 +
  SpellCheck.GoodToGo := True;
 +
</syntaxhighlight>
  
<syntaxhighlight>
+
12. Оставаясь в ObjectInspector, щелкните Form1, затем щелкните вкладку Events, затем дважды щелкните рядом с OnDestroy, это создаст событие OnDestroy и вставит код (см. код всего приложения)
{$MODE objfpc}{$H+}
 
unit hunspell;
 
  
{   Hunspell interface.
+
<syntaxhighlight lang=pascal>
    Based on code that seems to appear in lots of places in the Lazarus Forum
+
   SpellCheck.free;
    and elsewhere.
+
  SpellCheck := nil;
 +
</syntaxhighlight>
  
    With additions and corrections by dbannon to make it a little easier to use.
+
13. Затем в вашем коде разместите такие функции, как <code>ArrayValueCount</code> и т.д.
  
    As such, its assumed to be free to use by anyone for any purpose.
+
См. ниже код всего приложения, чтобы сравнить его с вашим.
}
 
  
{  A Unit to connect to the hunspell library and check some spelling.
+
<syntaxhighlight lang=pascal>
    First, create the class, it will try and find a library to load.
+
//SpellChecker by Raf20076, Poland 2019
    Check ErrorMessage.
 
    Then call SetDictionary(), with a full filename of the dictionary to use.
 
    If GoodToGo is true, you can call Spell() and Suggests()
 
    otherwise, look in ErrorString for what went wrong.
 
  
    Look in FindLibrary() for default locations of Library.
+
unit Unit1;
}
 
  
 +
{$mode objfpc}{$H+}
  
 
interface
 
interface
uses Classes, dynlibs;
+
 
 +
uses
 +
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls,
 +
  LazFileUtils, LCLProc, LazUtils, LazUtf8;
  
 
type
 
type
   THunspell_create = function(aff_file: PChar; dict_file: PChar): Pointer; cdecl;
+
   TForm1 = class(TForm)
  THunspell_destroy = procedure(spell: Pointer); cdecl;
+
     Button1: TButton;
  THunspell_spell = function(spell: Pointer; word: PChar): Boolean; cdecl;
+
     Label1: TLabel;
  THunspell_suggest = function(spell: Pointer; out slst: PPChar; word: PChar): Integer; cdecl;
+
     Label2: TLabel;
  THunspell_analyze = function(spell: Pointer; var slst: PPChar; word: PChar): Integer; cdecl;
+
     ListBox1: TListBox;
  THunspell_stem = function(spell: Pointer; var slst: PPChar; word: PChar): Integer; cdecl;
+
     ListBox2: TListBox;
  THunspell_free_list = procedure(spell: Pointer; var slst: PPChar; n: integer); cdecl;
+
     Memo1: TMemo;
  THunspell_get_dic_encoding = function(spell: Pointer): PChar; cdecl;
+
     procedure Button1Click(Sender: TObject);
  THunspell_add = function(spell: Pointer; word: PChar): Integer; cdecl;
+
     procedure FormCreate(Sender: TObject);
  THunspell_remove = function(spell: Pointer; word: PChar): Integer; cdecl;
+
     procedure FormDestroy(Sender: TObject);
 
 
  { THunspell }
 
 
 
  THunspell = class
 
  private
 
     Speller: Pointer;
 
        { Loads indicated library, returns False and sets ErrorMessage if something wrong }
 
     function LoadHunspellLibrary(LibraryName: AnsiString): Boolean;
 
  public
 
        { set to True if speller is ready to accept requests }
 
     GoodToGo : boolean;
 
        { empty if OK, contains an error message if something goes wrong }
 
     ErrorMessage : ANSIString;
 
            { Will have a full name to library if correctly loaded at create }
 
     LibraryFullName : string;
 
            { Will have a "first guess" as to where dictionaries are, poke another name in
 
            and call FindDictionary() if default did not work }
 
    constructor Create();
 
    destructor Destroy; override;
 
            { Returns True if word spelt correctly }
 
     function Spell(Word: string): boolean;
 
            { Returns with List full of suggestions how to spell Word }
 
     procedure Suggest(Word: string; List: TStrings);
 
            { untested }
 
     procedure Add(Word: string);
 
            { untested }
 
     procedure Remove(Word: string);
 
            { returns a full library name or '' if it cannot find anything suitable }
 
    function FindLibrary(out FullName : AnsiString) : boolean;
 
            { returns true if it successfully set the indicated dictionary }
 
    function SetDictionary(const FullDictName: string) : boolean;
 
    function SetNewLibrary(const LibName : string) : boolean;
 
 
   end;
 
   end;
  
var Hunspell_create: THunspell_create;
+
var
var Hunspell_destroy: THunspell_destroy;
+
  Form1: TForm1;
var Hunspell_spell: Thunspell_spell;
 
var Hunspell_suggest: Thunspell_suggest;
 
var Hunspell_analyze: Thunspell_analyze;
 
var Hunspell_stem: Thunspell_stem;
 
var Hunspell_get_dic_encoding: Thunspell_get_dic_encoding;
 
var Hunspell_add: THunspell_add;
 
var Hunspell_free_list: THunspell_free_list;
 
var Hunspell_remove: THunspell_remove;
 
 
 
var HunLibLoaded: Boolean = False;
 
var HunLibHandle: THandle;
 
  
 
implementation
 
implementation
  
uses LazUTF8, SysUtils, {$ifdef linux}Process, {$else} Forms, {$endif} LazFileUtils;
+
uses hunspell;//поместите hunspell.pas и hunspell.inc в папку вашего приложения
// Forms needed so we can call Application.~
+
              //из https://github.com/davidbannon/hunspell4pas
 +
             
 +
var
 +
  SpellCheck: THunspell;
  
{ THunspell }
+
{$R *.lfm}
  
function THunspell.LoadHunspellLibrary(libraryName: Ansistring): Boolean;
+
procedure TForm1.FormCreate(Sender: TObject);
 
begin
 
begin
    Result := false;
+
  SpellCheck := THunspell.Create(True);
    HunLibHandle := LoadLibrary(PAnsiChar(libraryName));
+
  SpellCheck.SetDictionary('pl_PL.dic');//загружаем словарь
    if HunLibHandle = NilHandle then
+
  SpellCheck.GoodToGo := True;
        ErrorMessage := 'Failed to load library ' + libraryName
 
    else begin
 
        Result := True;
 
        Hunspell_create := THunspell_create(GetProcAddress(HunLibHandle, 'Hunspell_create'));
 
        if not Assigned(Hunspell_create) then Result := False;
 
        Hunspell_destroy := Thunspell_destroy(GetProcAddress(HunLibHandle, 'Hunspell_destroy'));
 
        if not Assigned(Hunspell_destroy) then Result := False;
 
        Hunspell_spell := THunspell_spell(GetProcAddress(HunLibHandle, 'Hunspell_spell'));
 
        if not Assigned(Hunspell_spell) then Result := False;
 
        Hunspell_suggest := THunspell_suggest(GetProcAddress(HunLibHandle, 'Hunspell_suggest'));
 
        if not Assigned(Hunspell_suggest) then Result := False;
 
        Hunspell_analyze := THunspell_analyze(GetProcAddress(HunLibHandle, 'Hunspell_analyze'));  // not used here
 
        if not Assigned(Hunspell_analyze) then Result := False;
 
        Hunspell_stem := THunspell_stem(GetProcAddress(HunLibHandle, 'Hunspell_stem'));          // not used here
 
        if not Assigned(Hunspell_stem) then Result := False;
 
        Hunspell_get_dic_encoding := THunspell_get_dic_encoding(GetProcAddress(HunLibHandle, 'Hunspell_get_dic_encoding'));  // not used here
 
        if not Assigned(Hunspell_get_dic_encoding) then Result := False;
 
        Hunspell_free_list := THunspell_free_list(GetProcAddress(HunLibHandle, 'Hunspell_free_list'));
 
        if not Assigned(Hunspell_free_list) then Result := False;
 
        Hunspell_add := THunspell_add(GetProcAddress(HunLibHandle, 'Hunspell_add'));
 
        if not Assigned(Hunspell_add) then Result := False;
 
        Hunspell_remove := THunspell_remove(GetProcAddress(HunLibHandle, 'Hunspell_remove'));
 
        if not Assigned(Hunspell_remove) then Result := False;
 
        HunLibLoaded := Result;
 
    end;
 
    if ErrorMessage = '' then
 
        if not Result then ErrorMessage := 'Failed to find functions in ' + LibraryName;
 
 
end;
 
end;
  
constructor THunspell.Create();
+
{Извлекаем слова из строки: НЕсимволы, пробелы, возврат каретки}
begin
 
    ErrorMessage := '';
 
    if Not FindLibrary(LibraryFullName) then begin
 
        ErrorMessage := 'Cannot find Hunspell library';
 
        exit();
 
    end;
 
    LoadHunspellLibrary(LibraryFullName);    // will flag any errors it finds
 
    Speller := nil;          // we are not GoodToGo yet, need a dictionary ....
 
end;
 
  
destructor THunspell.Destroy;
+
function ArrayValueCount(const InputArray: Array of string): Integer;
 +
{Подсчет элементов в массиве}
 +
var
 +
  i:Integer;
 
begin
 
begin
    if (HunLibHandle <> 0) and HunLibLoaded then begin
+
  result := 0;
        if Speller<>nil then hunspell_destroy(Speller);
+
  for i := low(InputArray) to high(InputArray) do
        Speller:=nil;
+
    if InputArray[i] <> ' ' then // 'между ними один пробел'
        if HunLibHandle <> 0 then FreeLibrary(HunLibHandle);
+
      inc(result);
        HunLibLoaded := false;
 
    end;
 
    inherited Destroy;
 
 
end;
 
end;
  
function THunspell.Spell(Word: string): boolean;
+
function StripOffNonCharacter(const aString: string): string;
 +
{Удаляем НЕсимволы из строки}
 +
var
 +
  a: Char;
 
begin
 
begin
    Result := hunspell_spell(Speller, PChar(Word))
+
  Result := '';
 +
  for a in aString do begin //под знаками препинания цифры, которые нужно удалить из строки
 +
      if not CharInSet( a, ['.', ',', ';', ':', '!', '/',
 +
      '?', '@', '#', '$', '%', '&', '*', '(', ')', '{',
 +
      '}', '[', ']', '-', '\', '|', '<', '>', '''', '"', '^',
 +
      '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '_', '+',
 +
      '=', '~']) then //'„', '”'])эти метки делают ошибку: ожидается порядковое выражение, необходимо исправить
 +
      begin
 +
        Result := Result + a;
 +
      end;
 +
  end;
 
end;
 
end;
  
procedure THunspell.Suggest(Word: string; List: TStrings);
 
var i, len: Integer;
 
SugList, Words: PPChar;
 
begin
 
    List.clear;
 
    try
 
        len := hunspell_suggest(Speller, SugList, PChar(Word));
 
        Words := SugList;
 
        for i := 1 to len do begin
 
            List.Add(Words^);
 
            Inc(PtrInt(Words), sizeOf(Pointer));
 
        end;
 
    finally
 
        Hunspell_free_list(Speller, SugList, len);
 
    end;
 
end;
 
  
procedure THunspell.Add(Word: string);
+
function ReplaceCarriageReturn(s: string) : string;
 +
{Заменяем возврат каретки одним пробелом}
 +
var
 +
  i: Integer;
 
begin
 
begin
    Hunspell_add(Speller, Pchar(Word));
+
  Result:=s;
 +
  for i := 1 to Length(Result) do
 +
    if Result[i] in [#3..#13] then
 +
      Result[i] := ' ';//'Между ними один пробел'
 
end;
 
end;
  
procedure THunspell.Remove(Word: string);
 
begin
 
    Hunspell_remove(Speller, Pchar(Word));
 
end;
 
  
function THunspell.FindLibrary(out FullName : ANSIString):boolean;
+
procedure TForm1.Button1Click(Sender: TObject);
 +
{Проверяем орфографию}
 
var
 
var
    {$ifdef LINUX} I : integer = 1; {$endif}
+
    i : Integer;
    Info : TSearchRec;
+
    MAX : Integer;
    Mask : ANSIString;
+
    FillInArrayWithWords:TStringArray;
 +
    FillInString1: String;
 +
    FillInString2: String;
 
begin
 
begin
     Result := False;
+
     ListBox1.clear;
     {$IFDEF LINUX}
+
     ListBox1.Items.Clear;
     // Assumes ldconfig always returns same format, better than searching several dirs
+
 
     if RunCommand('/bin/bash',['-c','ldconfig -p | grep hunspell'], FullName) then begin
+
     FillInString1 := ReplaceCarriageReturn(Memo1.Lines.Text);//берем текст из Memo1; заменяем возврат каретки
        while UTF8Pos(' ', FullName, I) <> 0 do inc(I);
+
     //одним пробелом (используя функцию ReplaceCarriageReturn) и помещаем внутрь FillInString1
        if I=1 then exit();
+
 
        UTF8Delete(FullName, 1, I-1);
+
    FillInString2 := StripOffNonCharacter(FillInString1);//удаляем все НЕсимволы из FillInString1
        UTF8Delete(FullName, UTF8Pos(#10, FullName, 1), 1);
+
    //(используя функцию StripOffNonCharacter) и помещаем строку без НЕсимволов внутрь FillInString2
        Result := True;
+
 
    end;
+
    FillInArrayWithWords := FillInString2.split(' '); //разделяем строку на слова с помощью ' ' одного пробела
    exit();
+
     //(используя .split) и помещаем слова по отдельности в массив FillInArrayWithWords
    {$ENDIF}
+
 
    {$IFDEF WINDOWS} // Look for a dll in application home dir.
+
     MAX := ArrayValueCount(FillInArrayWithWords); //узнаем, сколько элементов в массиве
    Mask := '*hunspell*.dll';
+
     //(используя функцию ArrayValueCount)
     FullName := ExtractFilePath(Application.ExeName);
 
    {$endif}
 
    {$ifdef DARWIN}
 
     Mask := 'libhunspell*';
 
    FullName := '/usr/lib/';
 
    {$endif}
 
    if FindFirst(FullName + Mask, faAnyFile and faDirectory, Info)=0 then begin
 
        FullName := FullName + Info.name;
 
        Result := True;
 
     end;
 
    FindClose(Info);
 
end;
 
  
function THunspell.SetDictionary(const FullDictName: string) : boolean;
+
     for i := 0 to MAX -1 do
var
+
        if not SpellCheck.Spell(FillInArrayWithWords[i]) then  
     FullAff : string;
+
            ListBox1.Items.add(FillInArrayWithWords[i]);
begin
+
     //Берем слово из массива и проверяем по словарю через hunspell (используя функцию SpellCheck.Spell)
    FullAff := FullDictName;
+
     //Если слова нет в словаре, показываем его в Listbox, как ошибку
    UTF8Delete(FullAff, UTF8Length(FullAff) - 2, 3);
 
    FullAff := FullAff + 'aff';
 
    if Speller <> Nil then
 
        hunspell_destroy(Speller);
 
     Speller := hunspell_create(PChar(FullAff), PChar(FullDictName));
 
     GoodToGo := Speller <> Nil;
 
    if not GoodToGo then
 
        ErrorMessage := 'Failed to set Dictionary ' + FullDictName;
 
    Result := GoodToGo;
 
 
end;
 
end;
  
function THunspell.SetNewLibrary(const LibName: string): boolean;
+
procedure TForm1.FormDestroy(Sender: TObject);
 
begin
 
begin
     LibraryFullName := LibName;
+
     SpellCheck.free;
     Result := LoadHunspellLibrary(LibraryFullName);
+
     SpellCheck := nil;
 
end;
 
end;
  
end.
+
end.
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Note that this Unit uses LazUTF8, LazFileUtils and Forms. If you wish to use it as a simple command line application, you might add LCL to Required Packages in the Project Inspector or drop back to the FPC versions of Pos() etc but at the expense of UTF8 compatibility. And you cannot use Forms to provide Application.ExeName.
+
Когда вы запустите свое приложение и введете какой-либо текст в Memo, а затем нажмете кнопку, приложение проверит, обнаружены ли какие-либо ошибки, и, если они будут найдены, отобразит их в ListBox. Основная проблема заключалась в том, как удалить возврат каретки и НЕсимволы, а затем как разбить текст на отдельные слова. Это непростая задача. Поэтому для этого есть три функции: функция <code>ReplaceCarriageReturn</code>, функция <code>StripOffNonCharacter</code> и функция <code>FillInString2.split</code>. Функция <code>FillInString2.split</code> на самом деле использует функцию <code>.split</code> из <code>SysUtils</code>. Надеюсь, код всего приложения не требует пояснений.
  
== Further Reading and Links ==
+
== Дальнейшее чтение и ссылки ==
  
 
https://github.com/hunspell/hunspell
 
https://github.com/hunspell/hunspell
  
https://github.com/Homebrew - probably sensible way to get hunspell on your mac if its not already there.
+
https://github.com/Homebrew - вероятно, разумный способ получить Hunspell на вашем Mac, если его еще нет.
  
https://github.com/tomboy-notes/tomboy-ng/releases - Contains The 64bit Windows DLL in a tomboy-ng_win64_<ver>.zip
+
https://github.com/tomboy-notes/tomboy-ng/releases - содержит 64-битную Windows DLL в tomboy-ng_win64_<ver>.zip
  
 
https://github.com/cutec-chris/hunspell
 
https://github.com/cutec-chris/hunspell

Latest revision as of 23:56, 4 October 2022

English (en) español (es) русский (ru)



Использование hunspell с Lazarus

Light bulb  Примечание: Эта страница актуальна по состоянию на август 2018 года, но все меняется .....

Эта страница посвящена использованию библиотеки hunspell с Lazarus. Он описывает модель, которая работает, вроде как. Вам почти наверняка понадобится внести некоторые изменения для ваших конкретных целей, но, надеюсь, эта страница послужит вам хорошим началом.

Во-первых, на форуме есть несколько ссылок на некоторый код, который будет работать с библиотекой hunspell. Модуль hunspell.pas в значительной степени основан на этих блоках кода. У большинства нет информации о лицензии, и делается предположение, что она является «общеизвестной» и, следовательно, свободна от каких-либо ограничений. Я добавил немного, что решает проблему поиска файлов библиотеки и словаря. И установил разумный интерфейс.

Кроме того, пользователь [rvk] с форума создал Windows 64-битную DLL, так как для пользователей Windows не было никакой альтернативы.

О библиотеке Hunspell

Hunspell - это активный проект с открытым исходным кодом, распространяемый по открытой лицензии Mozilla. Библиотека hunspell используется в таких продуктах, как Libra Office, Open Office и Firefox. Его можно заставить работать на Windows, Linux и Mac (и, возможно, на кучах других платформ). См. ссылки на платформоспецифичные страницы ниже. Словари Hunspell легко доступны и, возможно, уже установлены на многих машинах. Даже если вы не можете получить доступ к библиотеке другого приложения, вы можете использовать его словарь.

Словари Hunspell поставляются в виде пары файлов *.dic и *.aff. Например, австралийский словарь состоит из en_AU.dic и en_AU.aff. Префикс 'en' обозначает его английский, а суффикс 'AU' говорит о его специфичности специально для Австралии. Как говорящий по-английски, я отмечаю, что словари en_US, кажется, всегда установлены, и я добавляю австралийские. Я не знаю, насколько распространен этот шаблон в не-англоязычных системах.

Словари можно найти здесь https://github.com/LibreOffice/dictionaries, а также некоторую информацию, связанную с этим, здесь https://wiki.documentfoundation.org/Development/Dictionaries

Замечание насчет словарей

В некоторых случаях для корректного отображения предлагаемых слов словари должны быть закодированы в UTF-8. Если вы заметили, что некоторые слова отображаются неправильно — например, яблоко на польском — это jabłko, а вы получаете jab�ko, — это означает, что словари pl_PL.aff и pl_PL.dic должны быть преобразованы в UTF-8. Чтобы преобразовать словари в UTF-8 в Linux Debian (это должно работать в любом Linux, конвертированные словари можно использовать в Windows - проверьте также эту ветку форума) выполните следующие действия:

1. Запустить терминал как root

  su

2. Если он еще не установлен, установите hunspell (hunspell-pl для польского словаря — подробнее на Debian Hunspell package)

  apt-get install hunspell
  apt-get install hunspell-pl

3. Перейдите в /usr/share/hunspell/, где хранятся словари, и создайте папку dic

  cd /usr/share/hunspell/
  mkdir dic

4. Преобразуйте, например, словарь pl_PL.aff и pl_PL.dic. Используйте ISO-8859-2 (для Восточной Европы), ISO-8859-1 (или ISO-8859-15) для Западной Европы, ISO-8859-5 для кириллицы и т.д.

  iconv -f ISO-8859-2 -t UTF-8 /usr/share/hunspell/pl_PL.aff | sed 's/^SET ISO8859-2$/SET UTF-8/g' > dic/pl_PL.aff
  iconv -f ISO-8859-2 -t UTF-8 /usr/share/hunspell/pl_PL.dic > dic/pl_PL.dic

5. Скопируйте папку dic или словари из папки dic в свое приложение.

Платформозависимость

Linux

Во многих дистрибутивах Linux по умолчанию установлен Hunspell вместе с соответствующими языковыми словарями. Если нет, то, вероятно, это просто случай использования менеджера пакетов дистрибутива. Если ничего не помогает, возьмите исходник с сайта hunspell github и создайте его самостоятельно. Пользователи Linux любят это.

Чтобы проверить, установлена ли у вас библиотека hunspell, попробуйте эту команду

 ldconfig -p | grep hunspell 

Точно так же вы можете найти некоторые словари с помощью

 ls -l /usr/share/hunspell 

Если это не сработает, попробуйте

 find /usr -name *.aff 

это займет немного больше времени.

Windows

Установка библиотеки hunspell на Windows является более серьезной проблемой. По-видимому, нет предварительно скомпилированного 'комплекта', и большинство приложений Windows, которые используют Hunspell, похоже, статически связывают его, поэтому не осталось никаких hunspell.dll для использования. Но просто, чтобы быть уверенным, попробуйте поискать *hunspell*.dll. На сайте Hunspell github приведен рецепт его создания, но он включает установку MSYS2 и довольно сложен. Получающаяся DLL также нуждается вдобавок в паре gcc DLL.

К счастью, пользователь rvk с форума Lazarus создал нам хорошую статически (т.е. автономно) связанную DLL-библиотеку с использованием Microsoft Visual Studio Community 2015. Таким образом, вы можете использовать и распространять эту DLL-библиотеку вместе с вашей программой, подпадающей под действие публичной лицензии Mozilla.

Вы найдете эту DLL в комплекте с файлом лицензии на https://github.com/davidbannon/hunspell4pas, щелкните «DLL», щелкните по файлу dll, и вы увидите кнопку «Загрузить». Не забудьте также получить файл лицензии, он должен распространяться, так или иначе, с вашим приложением.



Прим.перев.: Вы также можете посмотреть исходники интерфейса Hunspell для Lazarus здесь: https://github.com/cutec-chris/hunspell


Mac

На Mac'е автора, по-видимому, была установлена библиотека Hunspell при установке Sierra. Но, может быть, просто возможно, это пришло вместе с Firefox. Я хотел бы получить обратную связь .... [уже установлено на Mojave и Catalina]

Light bulb  Примечание: См https://opensource.apple.com/tarballs/hunspell/ для загрузки исходников v1.2.8.

Чтобы проверить, установлена ли у вас библиотека hunspell, попробуйте эту команду

 find / 2>&1 | grep "\hunspell"

она будет выполняться некоторое время, в зависимости от того, сколько файлов в вашей системе. Скорее всего, она найдет несколько файлов, включая некоторые, в вашем каталоге XCode. Однако конечным пользователям, вероятно, не будет установлен XCode. Один особенно интересный файл для меня был

 /usr/lib/libhunspell-1.2.dylib 

Версия 1.2 немного старше, чем где-либо, но работала нормально. Если вы не можете найти пригодную для использования библиотеку, я предлагаю вам установить его с помощью менеджера пакетов, такого как MacPorts, Fink или brew. Следующая проблема заключается в том, что вам понадобятся словари. Аналогичная команда

 find / 2>&1 | grep "\.aff"

опять же, медленная, она ищет по всему вашему диску. Я нашел команду

 /Applications/Firefox.app/Contents/Resources/dictionaries/en-US.aff 


И быстрый 'ls' заверил меня, что есть соответствующие файлы en-US.dic, так что все хорошо.

Более опытный пользователь Mac может предложить лучшие стратегии поиска. Пожалуйста!

Модуль Hunspell

При первоначальном создании этой страницы (2017?) я допустил серьезную ошибку и использовал код, у которого не было четкой лицензии или истории. Было высказано предположение, что тем самым я нарушил лицензию Hunspell, как и все, кто использовал ее с тех пор.

Чтобы исправить эту ситуацию, я выпустил новую версию Hunspell Wrapper, которая имеет довольно небольшую часть, только определения функций, с Hunspell (Лицензия: MPL 1.1/GPL 2.0/LGPL 2.1) и Hunspell Unit (Лицензия: Clear BSD License) в отдельных файлах. С точки зрения кодирования это почти идентично тому, что было здесь раньше.

См. https://github.com/davidbannon/hunspell4pas

Я удалил оболочку hunspell, которая раньше находилась на этой странице. Тот, что на Github выше, является заменой, вам нужны hunspell.pas и hunspell.inc. Оставшаяся часть файла представляет собой базовый test/demo проект Lazarus командной строки, который заменяет Demo 1.

Demo 2 в полном графическом интерфейсе

Демо графического интерфейса Lazarus имеет больше смысла и была протестирована на Linux, Mac и Windows. Но это немного сложнее, [чем] скопировать и вставить.

Для этой демо вам понадобится форма с двумя TMemo: Memo1 и MemoMsg. Кнопка ButtonSpell, Tlistbox Listbox1. Сделайте следующие обработчики событий: FormCreate для главной формы; дважды щелкните по Listbox1 и [дважды] кликните по ButtonSpell.

Сначала вы должны создать объект hunspell и посмотреть, нашел ли он свою библиотеку, вот пример метода FormCreate () ....

uses hunspell;
var
    Form1: TForm1;
    Sp: THunspell;
    DictPath : AnsiString;              

procedure TForm1.FormCreate(Sender: TObject);
begin
    SetDefaultDicPath();
    Sp := THunspell.Create();
    if Sp.ErrorMessage = '' then begin
        MemoMsg.append('Library Loaded =' + Sp.LibraryFullName);
        ButtonSpell.enabled := CheckForDict();
    end else
        MemoMsg.append(SP.ErrorMessage);
end;

В этом примере мы пишем сообщение о статусе в MemoMsg, это простой способ увидеть, что происходит. ButtonSpell НЕ включен, пока не будут установлены словари. Ожидаем этого ....

Теперь нам нужны два метода: один читает назначенный каталог и ищет возможные файлы словарей, другой управляет решениями. Если мы найдем только один словарный набор, используем его, если мы не найдем - пожалуемся. Но если мы найдем несколько, и это наиболее вероятно, мы должны спросить пользователя, какой словарь (то есть язык) он хочет использовать.

function TForm1.FindDictionary(const Dict : TStrings; const DPath : AnsiString) : boolean;
var
    Info : TSearchRec;
begin
    Dict.Clear;
    if FindFirst(AppendPathDelim(DPath) + '*.dic', faAnyFile and faDirectory, Info)=0 then begin
        repeat
            Dict.Add(Info.Name);
        until FindNext(Info) <> 0;
    end;
    FindClose(Info);
    Result := Dict.Count >= 1;
end;

function TForm1.CheckForDict() : boolean;
begin
    Result := False;
    EditDictPath.Caption := DictPathAlt;
    if not FindDictionary(ListBox1.Items, DictPath) then
        MemoMsg.Append('ERROR - no dictionaries found in ' + DictPath);//[прим.перев.]: словари в DictPath не найдены
    if ListBox1.Items.Count = 1 then begin                   // Один [словарь] вернулся точно.
        if not Sp.SetDictionary(AppendPathDelim(DictPath) + ListBox1.Items.Strings[0]) then
            MemoMsg.Append('ERROR ' + SP.ErrorMessage)
        else
            MemoMsg.Append('Dictionary set to ' + DictPath + ListBox1.Items.Strings[0]);// [прим.перев.]: словарь (первый из списка ListBox1) установлен в DictPath
    end;
    Result := SP.GoodToGo;   // если count был точно один или FindDict не вернул ничего и ничего не изменилось
end;

Ах, вы спросите, но где нам искать словари? К сожалению, у меня нет хорошего решения для этого. Вот где я нашел свой -

procedure TForm1.SetDefaultDicPath();
begin
    {$ifdef LINUX}
    DictPath := '/usr/share/hunspell/';
    {$ENDIF}
    {$ifdef WINDOWS}
    DictPath := ExtractFilePath(Application.ExeName);
    //DictPath := 'C:\Program Files\LibreOffice 5\share\extensions\dict-en\';
    {$ENDIF}
    {$ifdef DARWIN}
    DictPath := '/Applications/Firefox.app/Contents/Resources/dictionaries/';
    //DictPathAlt := ExtractFilePath(Application.ExeName);
    {$endif}
end;

Возможно, если другие пользователи сообщат, где они нашли пригодные для использования словари Hunspell, мы можем составить список для каждой платформы. Или просто выберите легкий путь и попросите пользователя найти несколько словарей и поместить их в каталог приложений на Windows и Mac. Ваши мысли очень приветствуются ....

Пока, если в указанном каталоге есть ровно один словарь, все хорошо. Но что, если их несколько? Наш ListBox1 содержит их список, если пользователь дважды щелкнет один из них, он вызовет этот метод -

procedure TForm1.ListBox1DblClick(Sender: TObject);
begin
    if ListBox1.ItemIndex > -1 then
        ButtonSpell.enabled := Sp.SetDictionary( AppendPathDelim(DictPath) + ListBox1.Items.Strings[ListBox1.ItemIndex]);
    if SP.ErrorMessage = '' then begin
        MemoMsg.Append('Good To Go =' + booltostr(Sp.GoodToGo, True));
        MemoMsg.Append('Dictionary set to ' + AppendPathDelim(DictPath) + ListBox1.Items.Strings[ListBox1.ItemIndex]);
    end else
        MemoMsg.append('ERROR ' + SP.ErrorMessage);
end;

Предполагая, что у нас теперь есть все, что нужно, мы можем нажать кнопку ButtonSpell и вызвать это -

procedure TForm1.ButtonSpellClick(Sender: TObject);
begin
    if not Sp.Spell(Edit1.text) then begin
        Memo1.Lines.BeginUpdate;
        Sp.Suggest('badspeller', Memo1.lines);
        Memo1.Lines.EndUpdate;
    end else
        Memo1.Lines.Clear;
end;

Memo1 теперь содержит несколько советов о лучших способах написания [слова] неграмотному!

Важно! Не забудьте освободить наш объект hunspeller, утечки памяти - зло!

procedure TForm1.FormDestroy(Sender: TObject);
begin
    Sp.free;
    Sp := nil;
end;

Этот модуль делает значительно больше, но он представлен здесь в его наиболее урезанной форме для удобства чтения.

Light bulb  Примечание: для новичков в Lazarus, методы с "(Sender: TObject)", показанные выше, не могут быть просто вставлены в ваш исходник, сначала используйте инспектор объектов формы, чтобы создать события, а затем вставьте мой пример кода в метод.

Demo 3 - Lazspell - Tmemo

В этом примере использовался компонент TMemo.

lazspell.gif

Lazspell - пример проверки орфографии - из https://github.com/Raf20076/Lazspell

Demo 4 - Lazspell 2-version 2 - TRichMemo

В этом примере использовался компонент TRichMemo.

lazspell-ver2.gif

Lazspell 2 v2 - пример проверки орфографии - изm https://github.com/Raf20076/Lazspell-2-version-2

Demo 5 - Простая проверка орфографии

1. Запустите IDE Lazarus

2. Кликните Project -> New Project -> Choose -> Application. Вы только что создали новое приложение. Теперь сохраните его

3. Кликните File -> Save as. Выберите папку, в которой будет сохранено ваше приложение. Сначала будет сохранен project1.lpi, затем unit1.pasunit1.pas

4. Поместите hunspell.pas и hunspell.inc (from https://github.com/davidbannon/hunspell4pas) в вашу папку

5. Поместите libhunspell.dll в папку с вашим приложением (вы должны загрузить ее отсюда https://github.com/Raf20076/Lazspell или https://github.com/davidbannon/hunspell4pas) в любом случае или соберите ее самостоятельно.

6. Поместите словарь в папку приложения (оба файла), например pl_PL.aff, pl_PL.dic. Словари должны быть закодированы в UTF8. Скачать их можно отсюда https://github.com/Raf20076/Lazspell/tree/master/dict

7. Положите на Form1 компонент TButton (Button1) с вкладки Standard

8. Положите на Form1 компонен TMemo (Memo1) с вкладки Standard

9. Положите на Form1 компонен TListbox (ListBox1) с вкладки Standard (здесь будут отображаться слова с ошибками)

10. Кликните по кнопке Button1 на Form1 затем перейдите в ObjectInspector, щелкните по вкладке Events, затем дважды щелкните рядом с событием OnClik: это создаст событие OnClick, и код вставки (см. код всего приложения), начинающийся с

   
{Check spelling}
 var
     i : Integer;
     MAX : Integer;
     FillInArrayWithWords:TStringArray;
     FillInString1: String;
     FillInString2: String;

до

//Если слова нет в словаре, показать его в Listbox как ошибку

11. Перейдите в ObjectInspector и щелкните Form1, затем щелкните вкладку Events, затем дважды щелкните рядом с OnCreate, это создаст событие OnCreate и вставит код (см. код всего приложения)

   SpellCheck := THunspell.Create(True);
   SpellCheck.SetDictionary('pl_PL.dic');//загружаем словарь
   SpellCheck.GoodToGo := True;

12. Оставаясь в ObjectInspector, щелкните Form1, затем щелкните вкладку Events, затем дважды щелкните рядом с OnDestroy, это создаст событие OnDestroy и вставит код (см. код всего приложения)

  SpellCheck.free;
  SpellCheck := nil;

13. Затем в вашем коде разместите такие функции, как ArrayValueCount и т.д.

См. ниже код всего приложения, чтобы сравнить его с вашим.

//SpellChecker by Raf20076, Poland 2019

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls,
  LazFileUtils, LCLProc, LazUtils, LazUtf8;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    Label2: TLabel;
    ListBox1: TListBox;
    ListBox2: TListBox;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

uses hunspell;//поместите hunspell.pas и hunspell.inc в папку вашего приложения
              //из https://github.com/davidbannon/hunspell4pas
              
var
  SpellCheck: THunspell;

{$R *.lfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
   SpellCheck := THunspell.Create(True);
   SpellCheck.SetDictionary('pl_PL.dic');//загружаем словарь
   SpellCheck.GoodToGo := True;
end;

{Извлекаем слова из строки: НЕсимволы, пробелы, возврат каретки}

function ArrayValueCount(const InputArray: Array of string): Integer;
{Подсчет элементов в массиве}
var
  i:Integer;
begin
  result := 0;
  for i := low(InputArray) to high(InputArray) do
    if InputArray[i] <> ' ' then  // 'между ними один пробел'
      inc(result);
end;

function StripOffNonCharacter(const aString: string): string;
{Удаляем НЕсимволы из строки}
var
  a: Char;
begin
  Result := '';
  for a in aString do begin //под знаками препинания цифры, которые нужно удалить из строки
      if not CharInSet( a, ['.', ',', ';', ':', '!', '/',
      '?', '@', '#', '$', '%', '&', '*', '(', ')', '{',
      '}', '[', ']', '-', '\', '|', '<', '>', '''', '"', '^',
      '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '_', '+',
      '=', '~']) then //'„', '”'])эти метки делают ошибку: ожидается порядковое выражение, необходимо исправить
      begin
        Result := Result + a;
      end;
  end;
end;


function ReplaceCarriageReturn(s: string) : string;
{Заменяем возврат каретки одним пробелом}
var
  i: Integer;
begin
  Result:=s;
  for i := 1 to Length(Result) do
    if Result[i] in [#3..#13] then
      Result[i] := ' ';//'Между ними один пробел'
end;


procedure TForm1.Button1Click(Sender: TObject);
{Проверяем орфографию}
var
     i : Integer;
     MAX : Integer;
     FillInArrayWithWords:TStringArray;
     FillInString1: String;
     FillInString2: String;
begin
    ListBox1.clear;
    ListBox1.Items.Clear;

    FillInString1 := ReplaceCarriageReturn(Memo1.Lines.Text);//берем текст из Memo1; заменяем возврат каретки
    //одним пробелом (используя функцию ReplaceCarriageReturn) и помещаем внутрь FillInString1

    FillInString2 := StripOffNonCharacter(FillInString1);//удаляем все НЕсимволы из FillInString1
    //(используя функцию StripOffNonCharacter) и помещаем строку без НЕсимволов внутрь FillInString2

    FillInArrayWithWords := FillInString2.split(' '); //разделяем строку на слова с помощью ' ' одного пробела
    //(используя .split) и помещаем слова по отдельности в массив FillInArrayWithWords

    MAX := ArrayValueCount(FillInArrayWithWords); //узнаем, сколько элементов в массиве 
    //(используя функцию ArrayValueCount)

    for i := 0 to MAX -1 do
        if not SpellCheck.Spell(FillInArrayWithWords[i]) then 
            ListBox1.Items.add(FillInArrayWithWords[i]);
    //Берем слово из массива и проверяем по словарю через hunspell (используя функцию SpellCheck.Spell)
    //Если слова нет в словаре, показываем его в Listbox, как ошибку
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
    SpellCheck.free;
    SpellCheck := nil;
end;

end.

Когда вы запустите свое приложение и введете какой-либо текст в Memo, а затем нажмете кнопку, приложение проверит, обнаружены ли какие-либо ошибки, и, если они будут найдены, отобразит их в ListBox. Основная проблема заключалась в том, как удалить возврат каретки и НЕсимволы, а затем как разбить текст на отдельные слова. Это непростая задача. Поэтому для этого есть три функции: функция ReplaceCarriageReturn, функция StripOffNonCharacter и функция FillInString2.split. Функция FillInString2.split на самом деле использует функцию .split из SysUtils. Надеюсь, код всего приложения не требует пояснений.

Дальнейшее чтение и ссылки

https://github.com/hunspell/hunspell

https://github.com/Homebrew - вероятно, разумный способ получить Hunspell на вашем Mac, если его еще нет.

https://github.com/tomboy-notes/tomboy-ng/releases - содержит 64-битную Windows DLL в tomboy-ng_win64_<ver>.zip

https://github.com/cutec-chris/hunspell