* update spellcheck unit with new stuff

git-svn-id: trunk@10274 -
This commit is contained in:
Almindor 2008-02-10 16:09:23 +00:00
parent 915b1bddb3
commit acc4d25f75

View File

@ -8,34 +8,84 @@ unit SpellCheck;
interface
uses
SysUtils, Aspell;
SysUtils, Classes, Aspell;
type
TSuggestionArray = array of string;
{ TSpellCheck }
TWordError = record
Word: string; // the word itself
Pos: LongWord; // word position in line
Length: LongWord; // word length
Suggestions: TSuggestionArray; // suggestions for the given word
end;
TLineErrors = array of TWordError;
TLineErrorsArray = array of TLineErrors;
TSpellCheck = class
{ TSpeller }
{ Abstract ancestor, don't use directly }
TSpeller = class // abstract class, basis for all checkers
protected
FSpeller: PAspellSpeller;
FMode: string;
FEncoding: string;
FLanguage: string;
procedure SetEncoding(const AValue: string);
procedure SetLanguage(const AValue: string);
procedure SetMode(const AValue: string);
procedure CreateSpeller;
procedure FreeSpeller;
procedure CreateSpeller; virtual; abstract;
procedure FreeSpeller; virtual; abstract;
public
constructor Create;
destructor Destroy; override;
function SpellCheck(const Word: string): TSuggestionArray;
public
property Mode: string read FMode write SetMode;
property Encoding: string read FEncoding write SetEncoding;
property Language: string read FLanguage write SetLanguage;
end;
{ TWordSpeller }
{ Basic spelling class for spelling single words without context }
TWordSpeller = class(TSpeller) // class for simple per-word checking
private
FSpeller: PAspellSpeller;
protected
procedure CreateSpeller; override;
procedure FreeSpeller; override;
public
function SpellCheck(const Word: string): TSuggestionArray; // use to check single words, parsed out by you
end;
{ TDocumentSpeller }
{ This speller is used to spellcheck lines or even whole documents.
It is usefull when different mode (like "tex") is used so you can pass
everything to aspell and let it take care of the context }
TDocumentSpeller = class(TWordSpeller)
private
FChecker: PAspellDocumentChecker;
FLineErrors: TLineErrorsArray;
FNameSuggestions: Boolean;
function GetLineErrors(i: Integer): TLineErrors;
function GetLineErrorsCount: Integer;
protected
procedure CreateSpeller; override;
procedure FreeSpeller; override;
procedure DoNameSuggestions(const Word: string; var aWordError: TWordError);
public
constructor Create;
function CheckLine(const aLine: string): TLineErrors;
function CheckDocument(const FileName: string): Integer; // returns number of spelling errors found or -1 for error
function CheckDocument(aStringList: TStringList): Integer; // returns number of spelling errors found or -1 for error
procedure Reset;
public
property LineErrors[i: Integer]: TLineErrors read GetLineErrors;
property LineErrorsCount: Integer read GetLineErrorsCount;
property NameSuggestions: Boolean read FNameSuggestions write FNameSuggestions;
end;
implementation
const
@ -50,27 +100,43 @@ begin
Result := DEFAULT_LANGUAGE;
end;
{ TSpellCheck }
{ TSpeller }
procedure TSpellCheck.SetEncoding(const AValue: string);
procedure TSpeller.SetEncoding(const AValue: string);
begin
FEncoding := aValue;
CreateSpeller;
end;
procedure TSpellCheck.SetLanguage(const AValue: string);
procedure TSpeller.SetLanguage(const AValue: string);
begin
FLanguage := aValue;
CreateSpeller;
end;
procedure TSpellCheck.SetMode(const AValue: string);
procedure TSpeller.SetMode(const AValue: string);
begin
FMode := aValue;
CreateSpeller;
end;
procedure TSpellCheck.CreateSpeller;
constructor TSpeller.Create;
begin
FEncoding := DEFAULT_ENCODING;
FLanguage := GetDefaultLanguage;
FMode := DEFAULT_MODE;
CreateSpeller;
end;
destructor TSpeller.Destroy;
begin
FreeSpeller;
end;
{ TWordSpeller }
procedure TWordSpeller.CreateSpeller;
var
Config: Paspellconfig;
Error: Paspellcanhaveerror;
@ -95,7 +161,7 @@ begin
FSpeller := to_aspell_speller(Error);
end;
procedure TSpellCheck.FreeSpeller;
procedure TWordSpeller.FreeSpeller;
begin
if Assigned(FSpeller) then begin
delete_aspell_speller(FSpeller);
@ -103,21 +169,7 @@ begin
end;
end;
constructor TSpellCheck.Create;
begin
FEncoding := DEFAULT_ENCODING;
FLanguage := GetDefaultLanguage;
FMode := DEFAULT_MODE;
CreateSpeller;
end;
destructor TSpellCheck.Destroy;
begin
FreeSpeller;
end;
function TSpellCheck.SpellCheck(const Word: string): TSuggestionArray;
function TWordSpeller.SpellCheck(const Word: string): TSuggestionArray;
var
sgs: Paspellwordlist;
elm: Paspellstringenumeration;
@ -148,5 +200,121 @@ begin
end;
end;
{ TDocumentSpeller }
function TDocumentSpeller.GetLineErrors(i: Integer): TLineErrors;
begin
Result := FLineErrors[i];
end;
function TDocumentSpeller.GetLineErrorsCount: Integer;
begin
Result := Length(FLineErrors);
end;
procedure TDocumentSpeller.CreateSpeller;
var
Error: PAspellCanHaveError;
begin
inherited CreateSpeller;
Error := new_aspell_document_checker(FSpeller);
if aspell_error_number(Error) <> 0 then
raise Exception.Create('Error on checker creation: ' + aspell_error_message(Error))
else
FChecker := to_aspell_document_checker(Error);
end;
procedure TDocumentSpeller.FreeSpeller;
begin
if Assigned(FChecker) then begin
delete_aspell_document_checker(FChecker);
FChecker := nil;
end;
inherited FreeSpeller;
end;
procedure TDocumentSpeller.DoNameSuggestions(const Word: string;
var aWordError: TWordError);
begin
aWordError.Suggestions := SpellCheck(Word);
end;
constructor TDocumentSpeller.Create;
begin
inherited Create;
FNameSuggestions := True;
end;
function TDocumentSpeller.CheckLine(const aLine: string): TLineErrors;
const
CHUNK_SIZE = 10;
var
i, Count: Integer;
Token: AspellToken;
begin
aspell_document_checker_process(FChecker, pChar(aLine), Length(aLine));
SetLength(Result, CHUNK_SIZE);
i := 0;
Count := 0;
repeat
Token := aspell_document_checker_next_misspelling(FChecker);
if Token.len > 0 then begin
if Length(Result) <= i then
SetLength(Result, Length(Result) + CHUNK_SIZE);
Result[i].Word := Copy(aLine, Token.offset + 1, Token.len);
Result[i].Pos := Token.offset + 1; // C goes from 0, we go from 1
Result[i].Length := Token.len;
if FNameSuggestions then
DoNameSuggestions(Copy(aLine, Token.offset + 1, Token.len), Result[i]);
Inc(Count);
end;
Inc(i);
until Token.len = 0;
SetLength(Result, Count);
end;
function TDocumentSpeller.CheckDocument(const FileName: string): Integer;
var
s: TStringList;
begin
Result := 0;
if FileExists(FileName) then try
s := TStringList.Create;
s.LoadFromFile(FileName);
Result := CheckDocument(s);
finally
s.Free;
end;
end;
function TDocumentSpeller.CheckDocument(aStringList: TStringList): Integer;
var
i: Integer;
begin
Result := 0;
SetLength(FLineErrors, aStringList.Count);
for i := 0 to aStringList.Count - 1 do begin
FLineErrors[i] := CheckLine(aStringList[i]);
Inc(Result, Length(FLineErrors[i]));
end;
end;
procedure TDocumentSpeller.Reset;
begin
aspell_document_checker_reset(FChecker);
end;
end.