Recent

Author Topic: Hunspell Spelling example doesn't work  (Read 7342 times)

Raf20076

  • Full Member
  • ***
  • Posts: 173
    • https://github.com/Raf20076
Hunspell Spelling example doesn't work
« on: February 15, 2019, 07:58:17 am »
Hi Guys
 I'm trying to uses spelling hunspell example from http://wiki.lazarus.freepascal.org/spelling for windows 7 (32bit) - but I've got errors
This is my  code  (I use unit1 - program and hunspell unit in my project).

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, hunspell;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     Button1: TButton;
  16.     ButtonSpell: TButton;
  17.     EditDictPath: TEdit;
  18.     ListBox1: TListBox;
  19.     ListBox: TListBox;
  20.     Memo1: TMemo;
  21.     MemoMsg: TMemo;
  22.     procedure ButtonSpellClick(Sender: TObject);
  23.     procedure FormCreate(Sender: TObject);
  24.     procedure FormDestroy(Sender: TObject);
  25.     procedure ListBox1DblClick(Sender: TObject);
  26.     procedure SetDefaultDicPath();
  27.    
  28.  
  29.   private
  30.  
  31.   public
  32.  
  33.   end;
  34.  
  35. var
  36.   Form1: TForm1;
  37.   Sp: THunspell;
  38.   DictPath : AnsiString;
  39.  
  40.  
  41. implementation
  42.  
  43.  
  44.  
  45. {$R *.lfm}
  46.  
  47. { TForm1 }
  48.  
  49.  
  50.  
  51. procedure TForm1.FormCreate(Sender: TObject);
  52.  
  53. begin
  54.     SetDefaultDicPath();
  55.     Sp := THunspell.Create();
  56.     if Sp.ErrorMessage = '' then begin
  57.         MemoMsg.append('Library Loaded =' + Sp.LibraryFullName);
  58.         ButtonSpell.enabled := CheckForDict();
  59.     end else
  60.         MemoMsg.append(SP.ErrorMessage);
  61. end;
  62.  
  63.  
  64.  
  65.  
  66. function TForm1.FindDictionary(const Dict : TStrings; const DPath : AnsiString) : boolean;
  67. var
  68.     Info : TSearchRec;
  69. begin
  70.     Dict.Clear;
  71.     if FindFirst(AppendPathDelim(DPath) + '*.dic', faAnyFile and faDirectory, Info)=0 then begin
  72.         repeat
  73.             Dict.Add(Info.Name);
  74.         until FindNext(Info) <> 0;
  75.     end;
  76.     FindClose(Info);
  77.     Result := Dict.Count >= 1;
  78. end;
  79. function TForm1.CheckForDict(): boolean;
  80. begin
  81.     Result := False;
  82.     //EditDictPath.Caption := DictPathAlt;
  83.     if not FindDictionary(ListBox1.Items, DictPath) then
  84.         MemoMsg.Append('ERROR - no dictionaries found in ' + DictPath);
  85.     if ListBox1.Items.Count = 1 then begin                   // Exactly one returned.
  86.         if not Sp.SetDictionary(AppendPathDelim(DictPath) + ListBox1.Items.Strings[0]) then
  87.             MemoMsg.Append('ERROR ' + SP.ErrorMessage)
  88.         else
  89.             MemoMsg.Append('Dictionary set to ' + DictPath + ListBox1.Items.Strings[0]);
  90.     end;
  91.     Result := SP.GoodToGo;   // only true if count was exactly one or FindDict failed and nothing changed
  92. end;
  93. procedure TForm1.SetDefaultDicPath();
  94. begin
  95.     {$ifdef LINUX}
  96.     DictPath := '/usr/share/hunspell/';
  97.     {$ENDIF}
  98.     {$ifdef WINDOWS}
  99.     //DictPath := ExtractFilePath(Application.ExeName);
  100.     DictPath := 'C:\Users\Rafal\Desktop\MySpell2\dic';
  101.     {$ENDIF}
  102.     {$ifdef DARWIN}
  103.     //DictPath := '/Applications/Firefox.app/Contents/Resources/dictionaries/';
  104.     DictPathAlt := ExtractFilePath(Application.ExeName);
  105.     {$endif}
  106. end;
  107.  
  108.  
  109. procedure TForm1.ListBox1DblClick(Sender: TObject);
  110. begin
  111.    if ListBox1.ItemIndex > -1 then
  112.         ButtonSpell.enabled := Sp.SetDictionary( AppendPathDelim(DictPath) + ListBox1.Items.Strings[ListBox1.ItemIndex]);
  113.     if SP.ErrorMessage = '' then begin
  114.         MemoMsg.Append('Good To Go =' + booltostr(Sp.GoodToGo, True));
  115.         MemoMsg.Append('Dictionary set to ' + AppendPathDelim(DictPath) + ListBox1.Items.Strings[ListBox1.ItemIndex]);
  116.     end else
  117.         MemoMsg.append('ERROR ' + SP.ErrorMessage);
  118. end;
  119. procedure TForm1.ButtonSpellClick(Sender: TObject);
  120. begin
  121.   if not Sp.Spell(EditDictPath.text) then begin
  122.         Memo1.Lines.BeginUpdate;
  123.         Sp.Suggest('badspeller', Memo1.lines);
  124.         Memo1.Lines.EndUpdate;
  125.     end else
  126.         Memo1.Lines.Clear;
  127. end;
  128. procedure TForm1.FormDestroy(Sender: TObject);
  129. begin
  130.     Sp.free;
  131.     Sp := nil;
  132. end;
  133. end.
  134.  
  135.  

I've got errors

Code: Pascal  [Select][+][-]
  1. Kompilowany projekt, Obiekt docelowy: project1.exe: Kod wyjścia 1,Errors: 14,, Warnings: 1
  2. unit1.pas(59,32) Error: Identifier not found "CheckForDict"
  3. unit1.pas(67,17) Error: method identifier expected
  4. unit1.pas(72,18) Error: Identifier not found "AppendPathDelim"
  5. unit1.pas(74,22) Warning: Local variable "Info" of a managed type does not seem to be initialized
  6. unit1.pas(80,17) Error: method identifier expected
  7. unit1.pas(84,27) Error: Identifier not found "ListBox1"
  8. unit1.pas(85,9) Error: Identifier not found "MemoMsg"
  9. unit1.pas(86,8) Error: Identifier not found "ListBox1"
  10. unit1.pas(87,33) Error: Identifier not found "AppendPathDelim"
  11. unit1.pas(87,61) Error: Identifier not found "ListBox1"
  12. unit1.pas(88,13) Error: Identifier not found "MemoMsg"
  13. unit1.pas(90,13) Error: Identifier not found "MemoMsg"
  14. unit1.pas(90,62) Error: Identifier not found "ListBox1"
  15. unit1.pas(113,50) Error: Identifier not found "AppendPathDelim"
  16. unit1.pas(116,47) Error: Identifier not found "AppendPathDelim"
  17.  
  18.  
I don't know how to figure out?
If I add procedure

Code: Pascal  [Select][+][-]
  1. procedure CheckForDict;
  2. procedure FindDictionary;  
  3.  

I get errors
Code: Pascal  [Select][+][-]
  1. Kompilowany projekt, Obiekt docelowy: project1.exe: Kod wyjścia 1,Błędy: 8,, Ostrzeżenia: 1
  2. unit1.pas(59,46) Error: Incompatible type for arg no. 1: Got "untyped", expected "Boolean"
  3. unit1.pas(67,17) Error: method identifier expected
  4. unit1.pas(72,18) Error: Identifier not found "AppendPathDelim"
  5. unit1.pas(74,22) Warning: Local variable "Info" of a managed type does not seem to be initialized
  6. unit1.pas(80,17) Error: function header doesn't match any method of this class "CheckForDict:Boolean;"
  7. unit1.pas(27,15) Error: Found declaration: CheckForDict;
  8. unit1.pas(87,33) Error: Identifier not found "AppendPathDelim"
  9. unit1.pas(113,50) Error: Identifier not found "AppendPathDelim"
  10. unit1.pas(116,47) Error: Identifier not found "AppendPathDelim"
  11.  
  12.  

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: Hunspell Spelling example doesn't work
« Reply #1 on: February 15, 2019, 09:29:11 am »
I don't know how to figure out?
If I add procedure
So if you add those procedure to the interface, the number of errors decreases.
So you are on the right track (why did you doubt that  ;) )

But now look at what you added to the interface:
Code: Pascal  [Select][+][-]
  1. procedure CheckForDict;
  2. procedure FindDictionary;  
  3.  

Now look at the definitions in the implementation.
Code: Pascal  [Select][+][-]
  1. function TForm1.FindDictionary(const Dict : TStrings; const DPath : AnsiString) : boolean;
  2. ...
  3. procedure TForm1.SetDefaultDicPath();
Notice any difference? Why did you declare it a procedure in the interface and function in the implementation for FindDictionary?

If you fix that (i.e. also function FindDictionary), you will get even less errors.

Try it and post the new code here with any remaining errors you didn't understand.

(Compile errors are one of the easiest to fix because you can just fix them one by one)

dbannon

  • Hero Member
  • *****
  • Posts: 2786
    • tomboy-ng, a rewrite of the classic Tomboy
Re: Hunspell Spelling example doesn't work
« Reply #2 on: February 15, 2019, 11:48:04 am »
Hi Raf, for example, you'll need to make CheckForDict(); a function, that is, a method that returns a value.  Code that works is included on the page, if you want it to all work as described you need to use all the code on the page. Its described bit by bit because its likely you will want to use some parts differently.

Feel free to poke around in tomboy-ng, link below, to see how it works as part of a whole system.

And feel free to ask more questions !

Davo



Lazarus 3, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

Raf20076

  • Full Member
  • ***
  • Posts: 173
    • https://github.com/Raf20076
Re: Hunspell Spelling example doesn't work
« Reply #3 on: February 15, 2019, 09:24:46 pm »
Hi Guys - I sort it out

When the spelling form is launch you can see that some letters (and words) are not showed correctly - for example Polish word - (apple - jb?ko) The Polish letter ł is marked as a question mark. It means that Polish dictionaries pl_PL.aff and pl_PL.dic in not in utf8. These dictionaries have to be converted into utf8.

SOLLUTION

I don't know how to covert dictionaries into utf8 under Windows
so I did it in Linux Debian (they can be used in Windows).

Some info could be found on https://github.com/atom/spell-check/issues/161

In order to work - you must convert dictionaries into utf8.

But If you want to convert dictionaries by yourself into utf8 do

1. Start terminal as a root

 
Code: Pascal  [Select][+][-]
  1.  su
  2.  
2. Go to /usr/share/hunspell/ where dictionaries are kept if not
   install hunspell (hunspell-pl is for Polish dictionary)
   more at https://packages.debian.org/search?keywords=hunspell

 
Code: Pascal  [Select][+][-]
  1.  
  2.    apt-get install hunspell
  3.    apt-get install hunspell-pl
  4.  
3. Go to the directory usr/share/hunspell/ and create folder dic

   
Code: Pascal  [Select][+][-]
  1.    cd /usr/share/hunspell/
  2.    mkdir dic

4. Convert for example dictionary pl_PL.aff and pl_PL.dic
   ISO-8859-2 is for (Eastern Europe) https://en.wikipedia.org/wiki/ISO/IEC_8859-2
   ISO-8859-1 is for (Western Europe) https://en.wikipedia.org/wiki/ISO/IEC_8859-1

Code: Pascal  [Select][+][-]
  1. 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
  2. iconv -f ISO-8859-2 -t UTF-8 /usr/share/hunspell/pl_PL.dic > dic/pl_PL.dic
  3.  

5. Copy your dic folder or dictionaries to your application }

This is my code for unit1

Code: Pascal  [Select][+][-]
  1.  
  2. //Raf20076, Poland,15-02-2019
  3. //Example from http://wiki.lazarus.freepascal.org/spelling
  4. //It was so difficult to sort it out but I managed somehow
  5. //What I discovered about dictionaries by myself
  6. {When the spelling form is launch you can see that some letters (and words)
  7. are not showed correctly - for example Polish word - (apple - jb?ko)
  8. The Polish letter ł is marked as a question mark.
  9. It means that Polish dictionaries pl_PL.aff and pl_PL.dic in not in utf8
  10. These dictionaries have to be converted into utf8.
  11.  
  12. SOLLUTION
  13.  
  14. I don't know how to covert dictionaries into utf8 under Windows
  15. so I did it in Linux Debian (they can be used in Windows).
  16.  
  17. Some info could be found on https://github.com/atom/spell-check/issues/161
  18.  
  19. In order to work - you must convert dictionaries into utf8.
  20.  
  21. These dictionaries collected in the folder has been already converted.
  22.  
  23. But If you want to convert dictionaries by yourself into utf8 do
  24.  
  25. 1. Start terminal as a root
  26.  
  27.    su
  28.  
  29. 2. Go to /usr/share/hunspell/ where dictionaries are kept if not
  30.    install hunspell (hunspell-pl is for Polish dictionary)
  31.    more at https://packages.debian.org/search?keywords=hunspell
  32.  
  33.    apt-get install hunspell
  34.    apt-get install hunspell-pl
  35.  
  36. 3. Go to the directory usr/share/hunspell/ and create folder dic
  37.  
  38.    cd /usr/share/hunspell/
  39.    mkdir dic
  40.  
  41. 4. Convert for example dictionary pl_PL.aff and pl_PL.dic
  42.    ISO-8859-2 is for (Eastern Europe) https://en.wikipedia.org/wiki/ISO/IEC_8859-2
  43.    ISO-8859-1 is for (Western Europe) https://en.wikipedia.org/wiki/ISO/IEC_8859-1
  44.  
  45. 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
  46. iconv -f ISO-8859-2 -t UTF-8 /usr/share/hunspell/pl_PL.dic > dic/pl_PL.dic
  47.  
  48. 5. Copy your dic folder or dictionaries to your application }
  49.  
  50. unit Unit1;
  51.  
  52. {$mode objfpc}{$H+}
  53.  
  54. interface
  55.  
  56. uses
  57.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, hunspell,
  58.   LazFileUtils;// LazFileUtils must be added for AppendPathDelim
  59.  
  60. type
  61.  
  62.   { TForm1 }
  63.  
  64.   TForm1 = class(TForm)
  65.     Button1: TButton;
  66.     ButtonSpell: TButton;
  67.     EditDictPath: TEdit;
  68.     Label1: TLabel;
  69.     Label2: TLabel;
  70.     Label3: TLabel;
  71.     Label4: TLabel;
  72.     ListBox1: TListBox;
  73.     Memo1: TMemo;
  74.     Memo2: TMemo;
  75.     MemoMsg: TMemo;
  76.     procedure Button1Click(Sender: TObject);
  77.     procedure ButtonSpellClick(Sender: TObject);
  78.     procedure FormCreate(Sender: TObject);
  79.     procedure FormDestroy(Sender: TObject);
  80.     procedure ListBox1DblClick(Sender: TObject);
  81.     procedure SetDefaultDicPath();
  82.     function CheckForDict(): boolean;
  83.     function FindDictionary(const Dict : TStrings; const DPath : AnsiString) : boolean;
  84.  
  85.     private
  86.  
  87.   public
  88.  
  89.   end;
  90.  
  91. var
  92.   Form1: TForm1;
  93.   Sp: THunspell;
  94.   DictPath : AnsiString;
  95.  
  96.  
  97. implementation
  98.  
  99.  
  100.  
  101. {$R *.lfm}
  102.  
  103. { TForm1 }
  104.  
  105.  
  106.  
  107. procedure TForm1.FormCreate(Sender: TObject);
  108.  
  109. begin
  110.     SetDefaultDicPath();
  111.     Sp := THunspell.Create();
  112.     if Sp.ErrorMessage = '' then begin
  113.         Memo2.append('Library Loaded =' + Sp.LibraryFullName);
  114.         ButtonSpell.enabled := CheckForDict();
  115.     end else
  116.         Memo2.append(SP.ErrorMessage);
  117. end;
  118.  
  119.  
  120.  
  121.  
  122. function TForm1.FindDictionary(const Dict : TStrings; const DPath : AnsiString) : boolean;
  123. var
  124.     Info : TSearchRec;
  125. begin
  126.     Dict.Clear;
  127.     if FindFirst(AppendPathDelim(DPath) + '*.dic', faAnyFile and faDirectory, Info)=0 then begin
  128.         repeat
  129.             Dict.Add(Info.Name);
  130.         until FindNext(Info) <> 0;
  131.     end;
  132.     FindClose(Info);
  133.     Result := Dict.Count >= 1;
  134. end;
  135. function TForm1.CheckForDict(): boolean;
  136. begin
  137.     Result := False;
  138.     EditDictPath.Caption := DictPath;
  139.     if not FindDictionary(ListBox1.Items, DictPath) then
  140.         Memo2.Append('ERROR - no dictionaries found in ' + DictPath);
  141.     if ListBox1.Items.Count = 1 then begin                   // Exactly one returned.
  142.         if not Sp.SetDictionary(AppendPathDelim(DictPath) + ListBox1.Items.Strings[0]) then
  143.             Memo2.Append('ERROR ' + SP.ErrorMessage)
  144.         else
  145.             Memo2.Append('Dictionary set to ' + DictPath + ListBox1.Items.Strings[0]);
  146.     end;
  147.     Result := SP.GoodToGo;   // only true if count was exactly one or FindDict failed and nothing changed
  148. end;
  149. procedure TForm1.SetDefaultDicPath();
  150. begin
  151.     {$ifdef LINUX}
  152.     DictPath := '/usr/share/hunspell/';
  153.     {$ENDIF}
  154.     {$ifdef WINDOWS}
  155.     DictPath := ExtractFilePath(Application.ExeName);
  156.     //DictPath := 'C:\Users\Rafal\Desktop\MySpell2\dic';
  157.     {$ENDIF}
  158.     {$ifdef DARWIN}
  159.     //DictPath := '/Applications/Firefox.app/Contents/Resources/dictionaries/';
  160.     DictPathAlt := ExtractFilePath(Application.ExeName);
  161.     {$endif}
  162. end;
  163.  
  164.  
  165. procedure TForm1.ListBox1DblClick(Sender: TObject);
  166. begin
  167.    if ListBox1.ItemIndex > -1 then
  168.         ButtonSpell.enabled := Sp.SetDictionary( AppendPathDelim(DictPath) + ListBox1.Items.Strings[ListBox1.ItemIndex]);
  169.     if SP.ErrorMessage = '' then begin
  170.         Memo2.Append('Good To Go =' + booltostr(Sp.GoodToGo, True));
  171.         Memo2.Append('Dictionary set to ' + AppendPathDelim(DictPath) + ListBox1.Items.Strings[ListBox1.ItemIndex]);
  172.     end else
  173.         Memo2.append('ERROR ' + SP.ErrorMessage);
  174. end;
  175. procedure TForm1.ButtonSpellClick(Sender: TObject);
  176. var
  177.     Suggestword : AnsiString;
  178. begin
  179.  
  180.   if not Sp.Spell(EditDictPath.text) then begin
  181.         Memo1.Lines.BeginUpdate;
  182.         Suggestword := (MemoMsg.Lines[0]);
  183.         Sp.Suggest(Suggestword, Memo1.lines);//Sollution at the moment
  184.         Memo1.Lines.EndUpdate;
  185.     end else
  186.         Memo1.Lines.Clear;
  187.  
  188.  
  189. end;
  190.  
  191. procedure TForm1.Button1Click(Sender: TObject);
  192. begin
  193.     Memo1.Lines.Clear;
  194.     MemoMsg.Lines.Clear;
  195. end;
  196.  
  197. procedure TForm1.FormDestroy(Sender: TObject);
  198. begin
  199.     Sp.free;
  200.     Sp := nil;
  201. end;
  202. end.
  203.  
  204.  

Code for unit called hunspell

Code: Pascal  [Select][+][-]
  1. {$MODE objfpc}{$H+}
  2. unit hunspell;
  3.  
  4. {   Hunspell interface.
  5.     Based on code that seems to appear in lots of places in the Lazarus Forum
  6.     and elsewhere.
  7.  
  8.     With additions and corrections by dbannon to make it a little easier to use.
  9.  
  10.     As such, its assumed to be free to use by anyone for any purpose.
  11. }
  12.  
  13. {   A Unit to connect to the hunspell library and check some spelling.
  14.     First, create the class, it will try and find a library to load.
  15.     Check ErrorMessage.
  16.     Then call SetDictionary(), with a full filename of the dictionary to use.
  17.     If GoodToGo is true, you can call Spell() and Suggests()
  18.     otherwise, look in ErrorString for what went wrong.
  19.  
  20.     Look in FindLibrary() for default locations of Library.
  21. }
  22.  
  23.  
  24. interface
  25. uses Classes, dynlibs;
  26.  
  27. type
  28.   THunspell_create = function(aff_file: PChar; dict_file: PChar): Pointer; cdecl;
  29.   THunspell_destroy = procedure(spell: Pointer); cdecl;
  30.   THunspell_spell = function(spell: Pointer; word: PChar): Boolean; cdecl;
  31.   THunspell_suggest = function(spell: Pointer; out slst: PPChar; word: PChar): Integer; cdecl;
  32.   THunspell_analyze = function(spell: Pointer; var slst: PPChar; word: PChar): Integer; cdecl;
  33.   THunspell_stem = function(spell: Pointer; var slst: PPChar; word: PChar): Integer; cdecl;
  34.   THunspell_free_list = procedure(spell: Pointer; var slst: PPChar; n: integer); cdecl;
  35.   THunspell_get_dic_encoding = function(spell: Pointer): PChar; cdecl;
  36.   THunspell_add = function(spell: Pointer; word: PChar): Integer; cdecl;
  37.   THunspell_remove = function(spell: Pointer; word: PChar): Integer; cdecl;
  38.  
  39.    { THunspell }
  40.  
  41.   THunspell = class
  42.   private
  43.     Speller: Pointer;
  44.         { Loads indicated library, returns False and sets ErrorMessage if something wrong }
  45.     function LoadHunspellLibrary(LibraryName: AnsiString): Boolean;
  46.   public
  47.             { set to True if speller is ready to accept requests }
  48.     GoodToGo : boolean;
  49.             { empty if OK, contains an error message if something goes wrong }
  50.     ErrorMessage : ANSIString;
  51.             { Will have a full name to library if correctly loaded at create }
  52.     LibraryFullName : string;
  53.             { Will have a "first guess" as to where dictionaries are, poke another name in
  54.             and call FindDictionary() if default did not work }
  55.     constructor Create();
  56.     destructor Destroy; override;
  57.             { Returns True if word spelt correctly }
  58.     function Spell(Word: string): boolean;
  59.             { Returns with List full of suggestions how to spell Word }
  60.     procedure Suggest(Word: string; List: TStrings);
  61.             { untested }
  62.     procedure Add(Word: string);
  63.             { untested }
  64.     procedure Remove(Word: string);
  65.             { returns a full library name or '' if it cannot find anything suitable }
  66.     function FindLibrary(out FullName : AnsiString) : boolean;
  67.             { returns true if it successfully set the indicated dictionary }
  68.     function SetDictionary(const FullDictName: string) : boolean;
  69.     function SetNewLibrary(const LibName : string) : boolean;
  70.   end;
  71.  
  72. var Hunspell_create: THunspell_create;
  73. var Hunspell_destroy: THunspell_destroy;
  74. var Hunspell_spell: Thunspell_spell;
  75. var Hunspell_suggest: Thunspell_suggest;
  76. var Hunspell_analyze: Thunspell_analyze;
  77. var Hunspell_stem: Thunspell_stem;
  78. var Hunspell_get_dic_encoding: Thunspell_get_dic_encoding;
  79. var Hunspell_add: THunspell_add;
  80. var Hunspell_free_list: THunspell_free_list;
  81. var Hunspell_remove: THunspell_remove;
  82.  
  83. var HunLibLoaded: Boolean = False;
  84. var HunLibHandle: THandle;
  85.  
  86. implementation
  87.  
  88. uses LazUTF8, SysUtils, {$ifdef linux}Process, {$else} Forms, {$endif} LazFileUtils;
  89. // Forms needed so we can call Application.~
  90.  
  91. { THunspell }
  92.  
  93. function THunspell.LoadHunspellLibrary(libraryName: Ansistring): Boolean;
  94. begin
  95.     Result := false;
  96.     HunLibHandle := LoadLibrary(PAnsiChar(libraryName));
  97.     if HunLibHandle = NilHandle then
  98.         ErrorMessage := 'Failed to load library ' + libraryName
  99.     else begin
  100.         Result := True;
  101.         Hunspell_create := THunspell_create(GetProcAddress(HunLibHandle, 'Hunspell_create'));
  102.         if not Assigned(Hunspell_create) then Result := False;
  103.         Hunspell_destroy := Thunspell_destroy(GetProcAddress(HunLibHandle, 'Hunspell_destroy'));
  104.         if not Assigned(Hunspell_destroy) then Result := False;
  105.         Hunspell_spell := THunspell_spell(GetProcAddress(HunLibHandle, 'Hunspell_spell'));
  106.         if not Assigned(Hunspell_spell) then Result := False;
  107.         Hunspell_suggest := THunspell_suggest(GetProcAddress(HunLibHandle, 'Hunspell_suggest'));
  108.         if not Assigned(Hunspell_suggest) then Result := False;
  109.         Hunspell_analyze := THunspell_analyze(GetProcAddress(HunLibHandle, 'Hunspell_analyze'));  // not used here
  110.         if not Assigned(Hunspell_analyze) then Result := False;
  111.         Hunspell_stem := THunspell_stem(GetProcAddress(HunLibHandle, 'Hunspell_stem'));           // not used here
  112.         if not Assigned(Hunspell_stem) then Result := False;
  113.         Hunspell_get_dic_encoding := THunspell_get_dic_encoding(GetProcAddress(HunLibHandle, 'Hunspell_get_dic_encoding'));   // not used here
  114.         if not Assigned(Hunspell_get_dic_encoding) then Result := False;
  115.         Hunspell_free_list := THunspell_free_list(GetProcAddress(HunLibHandle, 'Hunspell_free_list'));
  116.         if not Assigned(Hunspell_free_list) then Result := False;
  117.         Hunspell_add := THunspell_add(GetProcAddress(HunLibHandle, 'Hunspell_add'));
  118.         if not Assigned(Hunspell_add) then Result := False;
  119.         Hunspell_remove := THunspell_remove(GetProcAddress(HunLibHandle, 'Hunspell_remove'));
  120.         if not Assigned(Hunspell_remove) then Result := False;
  121.         HunLibLoaded := Result;
  122.     end;
  123.     if ErrorMessage = '' then
  124.         if not Result then ErrorMessage := 'Failed to find functions in ' + LibraryName;
  125. end;
  126.  
  127. constructor THunspell.Create();
  128. begin
  129.     ErrorMessage := '';
  130.     if Not FindLibrary(LibraryFullName) then begin
  131.         ErrorMessage := 'Cannot find Hunspell library';
  132.         exit();
  133.     end;
  134.     LoadHunspellLibrary(LibraryFullName);    // will flag any errors it finds
  135.     Speller := nil;           // we are not GoodToGo yet, need a dictionary ....
  136. end;
  137.  
  138. destructor THunspell.Destroy;
  139. begin
  140.     if (HunLibHandle <> 0) and HunLibLoaded then begin
  141.         if Speller<>nil then hunspell_destroy(Speller);
  142.         Speller:=nil;
  143.         if HunLibHandle <> 0 then FreeLibrary(HunLibHandle);
  144.         HunLibLoaded := false;
  145.     end;
  146.     inherited Destroy;
  147. end;
  148.  
  149. function THunspell.Spell(Word: string): boolean;
  150. begin
  151.     Result := hunspell_spell(Speller, PChar(Word))
  152. end;
  153.  
  154. procedure THunspell.Suggest(Word: string; List: TStrings);
  155. var i, len: Integer;
  156.         SugList, Words: PPChar;
  157. begin
  158.     List.clear;
  159.     try
  160.         len := hunspell_suggest(Speller, SugList, PChar(Word));
  161.         Words := SugList;
  162.         for i := 1 to len do begin
  163.             List.Add(Words^);
  164.             Inc(PtrInt(Words), sizeOf(Pointer));
  165.         end;
  166.     finally
  167.         Hunspell_free_list(Speller, SugList, len);
  168.     end;
  169. end;
  170.  
  171. procedure THunspell.Add(Word: string);
  172. begin
  173.     Hunspell_add(Speller, Pchar(Word));
  174. end;
  175.  
  176. procedure THunspell.Remove(Word: string);
  177. begin
  178.     Hunspell_remove(Speller, Pchar(Word));
  179. end;
  180.  
  181. function THunspell.FindLibrary(out FullName : ANSIString):boolean;
  182. var
  183.     {$ifdef LINUX} I : integer = 1; {$endif}
  184.     Info : TSearchRec;
  185.     Mask : ANSIString;
  186. begin
  187.     Result := False;
  188.     {$IFDEF LINUX}
  189.     // Assumes ldconfig always returns same format, better than searching several dirs
  190.     if RunCommand('/bin/bash',['-c','ldconfig -p | grep hunspell'], FullName) then begin
  191.         while UTF8Pos(' ', FullName, I) <> 0 do inc(I);
  192.         if I=1 then exit();
  193.         UTF8Delete(FullName, 1, I-1);
  194.         UTF8Delete(FullName, UTF8Pos(#10, FullName, 1), 1);
  195.         Result := True;
  196.     end;
  197.     exit();
  198.     {$ENDIF}
  199.     {$IFDEF WINDOWS}            // Look for a dll in application home dir.
  200.     Mask := '*hunspell*.dll';
  201.     FullName := ExtractFilePath(Application.ExeName);
  202.     {$endif}
  203.     {$ifdef DARWIN}
  204.     Mask := 'libhunspell*';
  205.     FullName := '/usr/lib/';
  206.     {$endif}
  207.     if FindFirst(FullName + Mask, faAnyFile and faDirectory, Info)=0 then begin
  208.         FullName := FullName + Info.name;
  209.         Result := True;
  210.     end;
  211.     FindClose(Info);
  212. end;
  213.  
  214. function THunspell.SetDictionary(const FullDictName: string) : boolean;
  215. var
  216.     FullAff : string;
  217. begin
  218.     FullAff := FullDictName;
  219.     UTF8Delete(FullAff, UTF8Length(FullAff) - 2, 3);
  220.     FullAff := FullAff + 'aff';
  221.     if Speller <> Nil then
  222.         hunspell_destroy(Speller);
  223.     Speller := hunspell_create(PChar(FullAff), PChar(FullDictName));
  224.     GoodToGo := Speller <> Nil;
  225.     if not GoodToGo then
  226.         ErrorMessage := 'Failed to set Dictionary ' + FullDictName;
  227.     Result := GoodToGo;
  228. end;
  229.  
  230. function THunspell.SetNewLibrary(const LibName: string): boolean;
  231. begin
  232.     LibraryFullName := LibName;
  233.     Result := LoadHunspellLibrary(LibraryFullName);
  234. end;
  235.  
  236. end.
  237.  

Code for project1.lpr

Code: Pascal  [Select][+][-]
  1. program project1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   {$IFDEF UNIX}{$IFDEF UseCThreads}
  7.   cthreads,
  8.   {$ENDIF}{$ENDIF}
  9.   Interfaces, // this includes the LCL widgetset
  10.   Forms, Unit1, hunspell
  11.   { you can add units after this };
  12.  
  13. {$R *.res}
  14.  
  15. begin
  16.   RequireDerivedFormResource:=True;
  17.   Application.Scaled:=True;
  18.   Application.Initialize;
  19.   Application.CreateForm(TForm1, Form1);
  20.   Application.Run;
  21. end.
  22.  
  23.  

In the folder where your application is put dictionaries and libhunspell.dll for 64 bit from here https://github.com/tomboy-notes/tomboy-ng/releases (choose tomboy-ng_win64_0.20.zip - the libhunspell.dll will be there)

dictionaries but you have to convert them into utf8 from here https://github.com/LibreOffice/dictionaries

From the code of unit1 you can figure out what components go on the form (look at picture attached).




dbannon

  • Hero Member
  • *****
  • Posts: 2786
    • tomboy-ng, a rewrite of the classic Tomboy
Re: Hunspell Spelling example doesn't work
« Reply #4 on: February 15, 2019, 09:58:42 pm »
You, Sir, have done very well indeed !

How about adding that info to our wiki page ?   Its not strictly FPC/Lazarus so, maybe you can put it somewhere else and link to it, or at least link to this forum thread ?

Valuable information either way !

Davo
Lazarus 3, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

Raf20076

  • Full Member
  • ***
  • Posts: 173
    • https://github.com/Raf20076
Re: Hunspell Spelling example doesn't work
« Reply #5 on: February 16, 2019, 08:11:33 am »
Hi Guys

I added some dictionaries converted  into UTF-8.

Languages:

Polish, Czech, Russian, German, Italian, English (US, GB), Portuguese, Spanish, French,

https://drive.google.com/file/d/14WZyys-ml74Ue4heqQ6N6aXYL1Y4g3I-/view?usp=sharing

dbannon

  • Hero Member
  • *****
  • Posts: 2786
    • tomboy-ng, a rewrite of the classic Tomboy
Re: Hunspell Spelling example doesn't work
« Reply #6 on: February 17, 2019, 04:46:07 am »
Hmm, thats pretty useful, will you continue to keep them there permanently ? I take it its a personal google drive share ?

I would not want to add them directly to the tomboy-ng source repo on git because it would make every source download heaps bigger. But I guess I could add them as a download from "releases" one way or another ?   Your efforts, you decide ?

Davo
Lazarus 3, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

Raf20076

  • Full Member
  • ***
  • Posts: 173
    • https://github.com/Raf20076
Re: Hunspell Spelling example doesn't work
« Reply #7 on: February 17, 2019, 07:43:13 am »
At the moment I will keep them on google drive but I realize that they should be hosted in places like github or sourseforge. Maybe in the future I will placed them there or attached to my projects. So Yes please If you want - you could add them as a download from "releases" or upload to proper place.

I hope that they will be useful.

PS. Once I had a situation where someone gave links for download and after a year it disappeared, so I understand that.

Thanks

Raf20076

  • Full Member
  • ***
  • Posts: 173
    • https://github.com/Raf20076
Re: Hunspell Spelling example doesn't work
« Reply #8 on: February 17, 2019, 11:24:09 am »
Hy guys

I added proper information about UTF-8 in wiki page http://wiki.lazarus.freepascal.org/spelling

Thanks

dbannon

  • Hero Member
  • *****
  • Posts: 2786
    • tomboy-ng, a rewrite of the classic Tomboy
Re: Hunspell Spelling example doesn't work
« Reply #9 on: February 17, 2019, 11:38:49 am »
.......
 So Yes please If you want - you could add them as a download from "releases" or upload to proper place.

Righto, we should work out a license and credit your work. Can you check the license on the original dictionaries ?  And then, if you are happy to use the same license, you should put that in a file called, perhaps "COPYING". And something about "dictionaries assembled and converted to UTF8 by <yourname>"  - Its up to you how you id yourself, name and an email address is normal but your call.

I'll say something in my release notes for each release of tomboy-ng along the lines of "Dictionaries for a number of languages have been converted to a suitable UTF8 format by <your name>. They are also, of course, suitable for any other similar project. Download from <somelink>".

Mind you, Raf, a github account is (still) free, be easy to release them yourself that way, be happy to advise .....

Davo
Lazarus 3, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

Raf20076

  • Full Member
  • ***
  • Posts: 173
    • https://github.com/Raf20076
Re: Hunspell Spelling example doesn't work
« Reply #10 on: February 17, 2019, 02:20:38 pm »
Hi guys

I have found utf8 dictionaries on github here https://github.com/wooorm/dictionaries
I didn't tested them but apparently they have been encoded in utf8.
I will check them later.

Raf20076

  • Full Member
  • ***
  • Posts: 173
    • https://github.com/Raf20076
Re: Hunspell Spelling example doesn't work
« Reply #11 on: February 23, 2019, 01:05:01 pm »
Hi Guys

I'm working on spelling checker using Hunspell Interface from here http://wiki.freepascal.org/spelling and It almost done but I have one problem - If word starts in MemoTypeText in new paragraph (when Enter button is pressed) then is listed as misspelt word.
I split words using code below with breakline #13 and space ' '

This is first paragraph

This is second paragraph

This from second paragraph is misspelt

Code: Pascal  [Select][+][-]
  1. b:= a.split([' ',#13]); //Split string into array using ' ' space and breakline #13

if I use code below

Code: Pascal  [Select][+][-]
  1. b:= a.split([' ']);

string is split using ' ' space but if the word is in new paragraph then this word is added to previous word for example

This is first paragraph

This is second paragraph

Last word paragraph in first paragraph is added to word This - misspelt word look like paragraphThis

Below my full  code. Have you got any ideas?

Code: Pascal  [Select][+][-]
  1.  
  2. {SPELLCHECKER - Raf20076, 21-02-2019, Poland}
  3. {This code uses Hunspell interface and
  4.  should work but if you have got any ideas
  5.  please leave comments or improve this  code}
  6.  
  7. unit Unit1;
  8.  
  9. {$mode objfpc}{$H+}
  10.  
  11. interface
  12.  
  13. uses
  14.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, hunspell,
  15.   LazFileUtils, LCLProc, LazUtils, LazUtf8;// LazFileUtils must be added for AppendPathDelim
  16.  
  17. type
  18.  
  19.   { TForm1 }
  20.  
  21.   TForm1 = class(TForm)
  22.     Clear: TButton;
  23.     ButtonChange: TButton;
  24.     ButtonSpell : TButton;
  25.     Label1: TLabel;
  26.     Label2: TLabel;
  27.     Label3: TLabel;
  28.     Label4: TLabel;
  29.     ListBoxDictionaries: TListBox;
  30.     ListBoxSugestion: TListBox;
  31.     ListBoxErrors: TListBox;
  32.     MemoTypeText: TMemo;
  33.     MemoInformation: TMemo;
  34.     procedure ClearClick(Sender: TObject);
  35.     procedure ButtonChangeClick(Sender: TObject);
  36.     procedure ButtonSpellClick(Sender: TObject);
  37.     procedure FormCreate(Sender: TObject);
  38.     procedure FormDestroy(Sender: TObject);
  39.     procedure ListBoxDictionariesClick(Sender: TObject);
  40.     procedure ListBoxErrorsClick(Sender: TObject);
  41.     procedure SetDefaultDicPath();
  42.     function CheckForDict(): boolean;
  43.     function FindDictionary(const Dict : TStrings; const DPath : AnsiString) : boolean;
  44.  
  45.     private
  46.  
  47.   public
  48.  
  49.   end;
  50.  
  51. var
  52.   Form1: TForm1;
  53.   Sp: THunspell;
  54.   DictPath : AnsiString;
  55.  
  56. implementation
  57.  
  58. {$R *.lfm}
  59.  
  60. { TForm1 }
  61.  
  62. procedure TForm1.FormCreate(Sender: TObject);
  63.  
  64. begin
  65.  
  66.     SetDefaultDicPath();
  67.     Sp := THunspell.Create();
  68.     if Sp.ErrorMessage = '' then begin
  69.         MemoInformation.append('Library Loaded =' + Sp.LibraryFullName);
  70.         ButtonSpell.enabled := CheckForDict();
  71.     end else
  72.         MemoInformation.append(SP.ErrorMessage);
  73. end;
  74.  
  75. function TForm1.FindDictionary(const Dict : TStrings; const DPath : AnsiString) : boolean;
  76. {Add dictionaries to the list}
  77. var
  78.     Info : TSearchRec;
  79. begin
  80.     Dict.Clear;
  81.     if FindFirst(AppendPathDelim(DPath) + '*.dic', faAnyFile and faDirectory, Info)=0 then begin
  82.         repeat
  83.             Dict.Add(Info.Name);
  84.         until FindNext(Info) <> 0;
  85.     end;
  86.     FindClose(Info);
  87.     Result := Dict.Count >= 1;
  88. end;
  89.  
  90. function TForm1.CheckForDict(): boolean;
  91. {Check if dictionary is in directory}
  92. begin
  93.  
  94.     Result := False;
  95.     if not FindDictionary(ListBoxDictionaries.Items, DictPath) then
  96.         MemoInformation.Append('ERROR - no dictionaries found in ' + DictPath);
  97.     if ListBoxDictionaries.Items.Count = 1 then begin                   // Exactly one returned.
  98.         if not Sp.SetDictionary(AppendPathDelim(DictPath) + ListBoxDictionaries.Items.Strings[0]) then
  99.             MemoInformation.Append('ERROR ' + SP.ErrorMessage)
  100.         else
  101.             MemoInformation.Append('Dictionary set to ' + DictPath + ListBoxDictionaries.Items.Strings[0]);
  102.     end;
  103.     Result := SP.GoodToGo;   // only true if count was exactly one or FindDict failed and nothing changed
  104. end;
  105. procedure TForm1.SetDefaultDicPath();
  106. {Dictonaries directory}
  107. begin
  108.     {$ifdef LINUX}
  109.     DictPath := '/usr/share/hunspell/';
  110.     {$ENDIF}
  111.     {$ifdef WINDOWS}
  112.     DictPath := ExtractFilePath(Application.ExeName); //Search dictionary in application folder
  113.     //DictPath := 'C:\MyApplication\dic'; //Or Search dictionary directly in this folder
  114.     {$ENDIF}
  115.     {$ifdef DARWIN}
  116.     //DictPath := '/Applications/Firefox.app/Contents/Resources/dictionaries/';
  117.     DictPathAlt := ExtractFilePath(Application.ExeName);
  118.     {$endif}
  119. end;
  120.  
  121. function ArrayValueCount(const InputArray: Array of string): Integer;
  122. {Count elements in array - needed for Check spelling}
  123. var
  124.     i:Integer;
  125.     begin
  126.         result := 0;
  127.         for i := low(InputArray) to high(InputArray) do
  128.         if InputArray[i] <> '' then
  129.             inc(result);
  130.     end;
  131.  
  132.  
  133. function StripOfNonCharacter(const aString: string): string;
  134. {Remove non characters - needed for Check spelling}
  135. var
  136.   a: Char;
  137. begin
  138.   Result := '';
  139.   for a in aString do begin //below punctuation marks, numbers etc to remove from string
  140.       if not CharInSet(a, ['.', ',', ';', ':', '!', '/',
  141.       '?', '@', '#', '$', '%', '&', '*', '(', ')', '{',
  142.       '}', '[', ']', '-', '\', '|', '<', '>', '''', '"', '^',
  143.       '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '_', '+',
  144.       '=', '~'])  then  //  '„'', '”'' canot be used - so if text has it
  145.       begin             //             they are listed as misspelt
  146.         Result := Result + a;
  147.       end;
  148.     end;
  149.  
  150. end;
  151. function TrimSpaces(s:string):string;
  152. {Trim spaces - trim many spaces between words into one space - needed for Check spelling }
  153.     begin
  154.       s:=utf8trim(s);
  155.       while utf8pos('  ',s)>0 do s:=utf8stringreplace(s, '  ',' ', [rfReplaceAll, rfIgnoreCase]);
  156.       result:=s;
  157.     end;
  158.  
  159. procedure TForm1.ButtonSpellClick(Sender: TObject);
  160.  {Check spelling}
  161.  var
  162.      b:TStringArray;
  163.      a : String;
  164.      c : String;
  165.      i : Integer;
  166.      MAX : Integer;
  167. begin
  168.     ListBoxErrors.clear;
  169.     c:=  TrimSpaces(MemoTypeText.lines.text);// trim many spaces into one space using function TrimSpaces
  170.     a := StripOfNonCharacter(c);//remove all non characters using function StripOfNonCharacter
  171.     b:= a.split([' ',#13]); //Split string into array using ' ' space and breakline #13
  172.                             //!!!If word starts in new paragraph (after Enter button pressed) it shows as an error!!!
  173.                             //How to fix it!?!!!!!!
  174.     MAX := ArrayValueCount(b); //Give how many elements are in array using function ArrayValueCount
  175.     for i := 0 to MAX do
  176.     if not Sp.Spell(b[i]) then ListBoxErrors.Items.add(b[i]) //Check string from array if it's in Sp.Spell
  177.                                                         //Sp.Spell function is in hunspell unit
  178.                                                         //if string is not in dictionary shows it in Listbox
  179.                                                         //as a misspelt word
  180. end;
  181.  
  182. procedure TForm1.ClearClick(Sender: TObject);
  183. {Clear windows}
  184. begin
  185.     MemoTypeText.Lines.Clear;
  186.     ListBoxSugestion.Clear;
  187.     ListBoxErrors.Clear;
  188. end;
  189.  
  190. procedure TForm1.ButtonChangeClick(Sender: TObject);
  191. var
  192.     Selected : AnsiString;
  193. begin
  194.   //Change
  195.     MemoTypeText.Clear;
  196.     if ListBoxSugestion.ItemIndex >= 0 then begin
  197.     MemoTypeText.Lines.BeginUpdate;
  198.     Selected := ListBoxSugestion.Items.Strings[ListBoxSugestion.ItemIndex];
  199.     MemoTypeText.Append(Selected);
  200.     MemoTypeText.Lines.EndUpdate;
  201.     end else
  202.     MemoInformation.Append(' nothing selected');
  203.  
  204.  
  205. end;
  206.  
  207. procedure TForm1.ListBoxDictionariesClick(Sender: TObject);
  208. begin
  209.   MemoInformation.Clear;
  210.   if ListBoxDictionaries.ItemIndex > -1 then
  211.         ButtonSpell.enabled := Sp.SetDictionary( AppendPathDelim(DictPath) + ListBoxDictionaries.Items.Strings[ListBoxDictionaries.ItemIndex]);
  212.     if SP.ErrorMessage = '' then begin
  213.         MemoInformation.Append('Good To Go =' + booltostr(Sp.GoodToGo, True));
  214.         MemoInformation.Append('Dictionary set to ' + AppendPathDelim(DictPath) + ListBoxDictionaries.Items.Strings[ListBoxDictionaries.ItemIndex]);
  215.     end else
  216.         MemoInformation.append('ERROR ' + SP.ErrorMessage);
  217. end;
  218.  
  219. procedure TForm1.ListBoxErrorsClick(Sender: TObject);
  220. var
  221.     Selected : AnsiString;
  222.  
  223. begin
  224.  
  225.    if ListBoxErrors.ItemIndex >= 0 then begin
  226.     Selected := ListBoxErrors.Items.Strings[ListBoxErrors.ItemIndex];
  227.     Sp.Suggest(Selected,ListBoxSugestion.Items);
  228.     MemoTypeText.Focused;
  229.     end else
  230.     MemoInformation.Append(' nothing selected');
  231.  
  232. end;
  233.  
  234.  procedure TForm1.FormDestroy(Sender: TObject);
  235. begin
  236.     Sp.free;
  237.     Sp := nil;
  238. end;
  239. end.
  240.  
  241.            
  242.  

Thaddy

  • Hero Member
  • *****
  • Posts: 14201
  • Probably until I exterminate Putin.
Re: Hunspell Spelling example doesn't work
« Reply #12 on: February 23, 2019, 01:15:27 pm »
For one you should use the LineEnding constant to be cross-platform, not #13 or #10 or #13#10
Code: Pascal  [Select][+][-]
  1. b:= a.split([' ',LineEnding]);
This is important, because the way you do it, there will be a dangling #10 on windows and on unix OS's #10 is used, not #13 which causes your problem., example:
Code: Pascal  [Select][+][-]
  1. {$mode delphi}
  2. uses sysutils;
  3. var
  4.   s:string = 'test me'+LineEnding+'too';
  5.   ss:array of string;
  6. begin
  7.   ss := s.split([' ',LineEnding]); // will split on windows with the whole CRLF #13#10 and on Mac / Linux /BSD etc with just #10
  8.   for s in ss do writeln(s);
  9. end.
« Last Edit: February 23, 2019, 01:47:46 pm by Thaddy »
Specialize a type, not a var.

Raf20076

  • Full Member
  • ***
  • Posts: 173
    • https://github.com/Raf20076
Re: Hunspell Spelling example doesn't work
« Reply #13 on: February 23, 2019, 03:35:49 pm »
So it should be like that? It seems to me it works but the last word in first paragraph sometimes is showed as misspell when there is no space after.
This is text.<No SPACE> then is misspel
This is text.  <TWO SPACES> after . is correct.

Sometimes I got error Access Violation..

Code: Pascal  [Select][+][-]
  1. const
  2.   LineEnding = #10;
  3.  
  4.  var
  5.      b:TStringArray;
  6.      a : String;
  7.      c : String;
  8.      i : Integer;
  9.      MAX : Integer;
  10. begin
  11.     ListBoxErrors.clear;
  12.     c:=  TrimSpaces(MemoTypeText.lines.text);// trim many spaces into one space using function TrimSpaces
  13.     a := StripOfNonCharacter(c);//remove all non characters using function StripOfNonCharacter
  14.     b:= a.split([' ',LineEnding]); //Split string into array using ' ' space and breakline #10
  15.                             //!!!If word starts in new paragraph (after Enter button pressed) it shows as an error!!!
  16.                             //How to fix it!?!!!!!!
  17.     MAX := ArrayValueCount(b); //Give how many elements are in array using function ArrayValueCount
  18.     for i := 0 to MAX do
  19.     if not Sp.Spell(b[i]) then ListBoxErrors.Items.add(b[i]) //Check string from array if it's in Sp.Spell
  20.                                                         //Sp.Spell function is in hunspell unit
  21.                                                         //if string is not in dictionary shows it in Listbox
  22.                                                         //as a misspelt word
« Last Edit: February 23, 2019, 03:56:30 pm by Raf20076 »

Thaddy

  • Hero Member
  • *****
  • Posts: 14201
  • Probably until I exterminate Putin.
Re: Hunspell Spelling example doesn't work
« Reply #14 on: February 23, 2019, 03:54:50 pm »
Code: Pascal  [Select][+][-]
  1.  for i := 0 to MAX-1 do /// should be like this or  to High(array)
  You count from zero.... High(b) equals MAX-1
You can probably solve both problems at once by doing it like this:
Code: Pascal  [Select][+][-]
  1. {$mode delphi}
  2. uses sysutils;
  3. var
  4.   s:string = 'test me'+LineEnding+'too';
  5.   ss:array of string;
  6. begin
  7.   ss := s.split([' ',LineEnding]); // will split on windows with the whole CRLF #13#10 and on Mac / Linux /BSD etc with just #10
  8.   for s in ss if s <>'' do writeln(s); //skip empty strings
  9. end.
The for in do syntax prevents you from making the indexing mistake I pointed out to you
« Last Edit: February 23, 2019, 04:05:59 pm by Thaddy »
Specialize a type, not a var.

 

TinyPortal © 2005-2018