git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.DevExpressVCL@55 05c56307-c608-d34a-929d-697000501d7a
4867 lines
157 KiB
ObjectPascal
4867 lines
157 KiB
ObjectPascal
{********************************************************************}
|
|
{ }
|
|
{ Developer Express Visual Component Library }
|
|
{ ExpressSpellChecker }
|
|
{ }
|
|
{ Copyright (c) 1998-2009 Developer Express Inc. }
|
|
{ ALL RIGHTS RESERVED }
|
|
{ }
|
|
{ The entire contents of this file is protected by U.S. and }
|
|
{ International Copyright Laws. Unauthorized reproduction, }
|
|
{ reverse-engineering, and distribution of all or any portion of }
|
|
{ the code contained in this file is strictly prohibited and may }
|
|
{ result in severe civil and criminal penalties and will be }
|
|
{ prosecuted to the maximum extent possible under the law. }
|
|
{ }
|
|
{ RESTRICTIONS }
|
|
{ }
|
|
{ THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES }
|
|
{ (DCU, OBJ, DLL, ETC.) ARE CONFIDENTIAL AND PROPRIETARY TRADE }
|
|
{ SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS }
|
|
{ LICENSED TO DISTRIBUTE THE EXPRESSSPELLCHECKER AND ALL }
|
|
{ ACCOMPANYING VCL CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY. }
|
|
{ }
|
|
{ THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED }
|
|
{ FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE }
|
|
{ COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE }
|
|
{ AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT }
|
|
{ AND PERMISSION FROM DEVELOPER EXPRESS INC. }
|
|
{ }
|
|
{ CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON }
|
|
{ ADDITIONAL RESTRICTIONS. }
|
|
{ }
|
|
{********************************************************************}
|
|
|
|
unit dxHunspellAffixes;
|
|
|
|
{$I cxVer.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
StrUtils, Math, SysUtils, Contnrs, dxHunspellUtils, dxHunspellWords,
|
|
dxHunspellTypes;
|
|
|
|
const
|
|
AffixTableSize = 256;
|
|
MaxLineLength = 8192;
|
|
DefaultCompoundPartLength = 3;
|
|
|
|
ExistentSuffixFlag = 1 shl 0;
|
|
ExistentPrefixFlag = 1 shl 1;
|
|
|
|
aoPrefixSuffixUnion = 1 shl 0;
|
|
aeUTF8 = 1 shl 1;
|
|
aoAffixFlagAliasTable = 1 shl 2;
|
|
aoAffixMorphologyTable = 1 shl 3;
|
|
aeLONGCOND = 1 shl 4;
|
|
|
|
HashSize = 256;
|
|
MaxFlagCount = 65536;
|
|
|
|
MaxConditionLength = 20;
|
|
|
|
type
|
|
|
|
TdxExistentAffixFlags = array[0..MaxFlagCount - 1] of Byte;
|
|
|
|
TdxStringData = record
|
|
Data: PAnsiChar;
|
|
Length: Integer;
|
|
end;
|
|
|
|
TdxReplaceTableItem = packed record
|
|
Initial: PAnsiChar;
|
|
Replacement: PAnsiChar;
|
|
end;
|
|
PdxReplaceArray = ^TdxReplaceArray;
|
|
TdxReplaceArray = array[0..0] of TdxReplaceTableItem;
|
|
|
|
TdxMapTableItem = packed record
|
|
CharacterSet: PAnsiChar;
|
|
Length: Integer;
|
|
end;
|
|
PdxMapArray = ^TdxMapArray;
|
|
TdxMapArray = array[0..0] of TdxMapTableItem;
|
|
|
|
TdxCompoundForbidPattern = record
|
|
Pattern: PAnsiChar;
|
|
Pattern2: PAnsiChar;
|
|
Pattern3: PAnsiChar;
|
|
Condition: Word;
|
|
Condition2: Word;
|
|
end;
|
|
PdxCompoundForbidPatternArray = ^TdxCompoundForbidPatternArray;
|
|
TdxCompoundForbidPatternArray = array[0..0] of TdxCompoundForbidPattern;
|
|
|
|
TdxHunspellAffixManager = class;
|
|
TdxAffix = class;
|
|
|
|
TdxAffixType = (atNone, atPrefix, atSuffix);
|
|
|
|
TdxCompoundWordPart = (cwpNone, cwpFirst, cwpLast, cwpOther);
|
|
|
|
TAffixTable = array [0..AffixTableSize - 1] of TdxAffix;
|
|
|
|
TWordFormArray = array [0..MAXWORDUTF8LEN + 4 - 1] of AnsiChar;
|
|
|
|
TAffixManagerFlagArray = array[0..MaxFlagCount - 1] of Boolean;
|
|
|
|
PdxAffixItem = ^TdxAffixItem;
|
|
TdxAffixItem = packed record
|
|
FStripString: PAnsiChar;
|
|
FAppendString: PAnsiChar;
|
|
FStripStringLength: Byte;
|
|
FAppendStringLength: Byte;
|
|
FConditionLength: Shortint;
|
|
FCompatibleFlags: TdxHunspellFlags;
|
|
FMorphologicalDescription: PAnsiChar;
|
|
LongCondition: Boolean;
|
|
case Integer of
|
|
1: (Condition: array [0..MaxConditionLength - 1] of AnsiChar);
|
|
2: (ConditionFirstPart: array [0..MaxConditionLength - 1] of AnsiChar;
|
|
ConditionSecondPart: PAnsiChar;)
|
|
end;
|
|
PdxAffixItemArray = ^TdxAffixItemArray;
|
|
TdxAffixItemArray = array[0..0] of TdxAffixItem;
|
|
|
|
PdxCompoundFlag = ^TdxCompoundFlag;
|
|
TdxCompoundFlag = record
|
|
Pattern: PdxAffixFlagsData;
|
|
Count: Integer;
|
|
Length: Integer;
|
|
end;
|
|
PdxCompoundFlagArray = ^TdxCompoundFlagArray;
|
|
TdxCompoundFlagArray = array[0..0] of TdxCompoundFlag;
|
|
|
|
PdxAffixCondition = ^TdxAffixCondition;
|
|
TdxAffixCondition = record
|
|
case Integer of
|
|
1: (Condition: array [0..MaxConditionLength - 1] of AnsiChar);
|
|
2: (ConditionFirstPart: array [0..MaxConditionLength - 1] of AnsiChar;
|
|
ConditionSecondPart: PAnsiChar);
|
|
end;
|
|
|
|
TdxSpellCheckerDataTable = class
|
|
private
|
|
FCurrentDataIndex: Integer;
|
|
FDataIdentifier: PAnsiChar;
|
|
FSize: Integer;
|
|
procedure FreeData;
|
|
protected
|
|
FData: Pointer;
|
|
function AddDataPiece(const APiece: PAnsiChar; ADataIndex,
|
|
APieceIndex: Integer): Boolean; virtual;
|
|
function IsAllPiecesFound(APieceIndex: Integer): Boolean; virtual;
|
|
function CheckDataType(const APiece: PAnsiChar): Boolean;
|
|
procedure FreeDataItems; virtual; abstract;
|
|
function GetDataIdentifier: PAnsiChar; virtual; abstract;
|
|
function GetDataItemSize: Integer; virtual; abstract;
|
|
function GetPieceQuantity: Integer; virtual; abstract;
|
|
procedure InitializeItem(Index: Integer); virtual;
|
|
function ReadDataHeader(ALine: PAnsiChar): Boolean;
|
|
function ParseHeader(ALine: PAnsiChar; out ATableSize: Integer): Boolean; virtual;
|
|
function ParseData(AAffixFileManager: TdxHunspellReader): Boolean;
|
|
public
|
|
constructor Create; overload;
|
|
constructor Create(ADataIdentifier: PAnsiChar); overload;
|
|
destructor Destroy; override;
|
|
function AllocateData(ASize: Integer): Boolean;
|
|
function ReadData(ALine: PAnsiChar; AAffixFileManager: TdxHunspellReader): Boolean;
|
|
property Count: Integer read FSize;
|
|
end;
|
|
|
|
TdxSpellCheckerDataLinkedTable = class(TdxSpellCheckerDataTable)
|
|
private
|
|
FWordBaseManager: TdxHunspellWordBaseManager;
|
|
FAffixManager: TdxHunspellAffixManager;
|
|
public
|
|
constructor Create(AWordBaseManager: TdxHunspellWordBaseManager;
|
|
AAffixManager: TdxHunspellAffixManager);
|
|
property AffixManager: TdxHunspellAffixManager read FAffixManager;
|
|
property WordBaseManager: TdxHunspellWordBaseManager read FWordBaseManager;
|
|
end;
|
|
|
|
TdxAffixItemTable = class(TdxSpellCheckerDataLinkedTable)
|
|
private
|
|
FAffixesIsCreated: Boolean;
|
|
FDecodedFlag: Word;
|
|
FExistentAffixFlags: TdxExistentAffixFlags;
|
|
FFlag: PAnsiChar;
|
|
FPrefixSuffixUnion: Boolean;
|
|
procedure AddLineRemainderToMorphologicDescription(ALine: PAnsiChar; ADataIndex: Integer);
|
|
function CheckFlag(ALine: PAnsiChar): Boolean;
|
|
function ConditionLength(ALine: PAnsiChar): Integer;
|
|
function EncodeAffixCondition(ALine: PAnsiChar; ADataIndex: Integer): Boolean;
|
|
function HasAffixFlagAliases: Boolean;
|
|
function HasAffixMorphologicAliases: Boolean;
|
|
function FlagIsNil: Boolean;
|
|
function FlagIsUnique(AFlag: Word): Boolean;
|
|
procedure FreeIfZero(var AString: TdxStringData);
|
|
function GetData: PdxAffixItemArray;
|
|
function GetItem(Index: Integer): TdxAffixItem;
|
|
function GetOptions(AItem: TdxAffixItem): ShortInt;
|
|
function IsReverseWritingDirection: Boolean;
|
|
procedure ParseAppendString(const ALine: PAnsiChar; ADataIndex: Integer);
|
|
function ParseAppendStringWithAffixes(const ALine: PAnsiChar; ADataIndex: Integer): Boolean;
|
|
function ParseCompatibleFlags(const ALine: PAnsiChar; ADataIndex: Integer): Boolean;
|
|
function ParseCondition(ALine: PAnsiChar; ADataIndex: Integer): Boolean;
|
|
function ParseFlag(ALine: PAnsiChar): Boolean;
|
|
function ParseMorphologicDescription(ALine: PAnsiChar; ADataIndex: Integer): Boolean;
|
|
procedure ParsePrefixSuffixUnion(ALine: PAnsiChar);
|
|
procedure ParseStripString(const ALine: PAnsiChar; ADataIndex: Integer);
|
|
function ParseTableSize(ALine: PAnsiChar; out ATableSize: Integer): Boolean;
|
|
procedure ProcessIgnoreChars(ALine: PAnsiChar);
|
|
procedure ProcessReverseString(ALine: PAnsiChar);
|
|
procedure RegisterCompatibleFlags(ADataIndex: Integer);
|
|
procedure ReverseCondition(ACondition: PAnsiChar);
|
|
procedure SetExisting;
|
|
protected
|
|
function AddDataPiece(const APiece: PAnsiChar; ADataIndex,
|
|
APieceIndex: Integer): Boolean; override;
|
|
function IsAllPiecesFound(APieceIndex: Integer): Boolean; override;
|
|
function IsComplexPrefixes: Boolean;
|
|
procedure BuildAffixes; virtual;
|
|
function ConditionContainsDuplicateInformation(strip: PAnsiChar; stripl: Integer;
|
|
const ACondition: PAnsiChar; out Contains: Boolean): Boolean; virtual; abstract;
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function GetDataItemSize: Integer; override;
|
|
function GetPieceQuantity: Integer; override;
|
|
procedure FreeDataItems; override;
|
|
function IsPrefix: Boolean; virtual; abstract;
|
|
function ParseHeader(ALine: PAnsiChar; out ATableSize: Integer): Boolean; override;
|
|
|
|
property Data: PdxAffixItemArray read GetData;
|
|
property Items[Index: Integer]: TdxAffixItem read GetItem; default;
|
|
public
|
|
constructor Create(AWordBaseManager: TdxHunspellWordBaseManager;
|
|
AAffixManager: TdxHunspellAffixManager; AExistentAffixFlags: TdxExistentAffixFlags);
|
|
destructor Destroy; override;
|
|
property Flag: PAnsiChar read FFlag;
|
|
end;
|
|
|
|
TdxPrefixItemTable = class(TdxAffixItemTable)
|
|
protected
|
|
function ConditionContainsDuplicateInformation(strip: PAnsiChar; stripl: Integer;
|
|
const ACondition: PAnsiChar; out Contains: Boolean): Boolean; override;
|
|
function IsPrefix: Boolean; override;
|
|
public
|
|
procedure BuildAffixes; override;
|
|
end;
|
|
|
|
TdxSuffixItemTable = class(TdxAffixItemTable)
|
|
protected
|
|
function ConditionContainsDuplicateInformation(strip: PAnsiChar; stripl: Integer;
|
|
const ACondition: PAnsiChar; out Contains: Boolean): Boolean; override;
|
|
function IsPrefix: Boolean; override;
|
|
public
|
|
procedure BuildAffixes; override;
|
|
end;
|
|
|
|
TdxBreakTable = class(TdxSpellCheckerDataTable)
|
|
private
|
|
procedure FillDefaultData;
|
|
function GetData: PdxPAnsiCharArray;
|
|
function GetItem(Index: Integer): PAnsiChar;
|
|
protected
|
|
function AddDataPiece(const APiece: PAnsiChar; ADataIndex,
|
|
APieceIndex: Integer): Boolean; override;
|
|
procedure FreeDataItems; override;
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function GetDataItemSize: Integer; override;
|
|
function GetPieceQuantity: Integer; override;
|
|
public
|
|
constructor Create;
|
|
property Data: PdxPAnsiCharArray read GetData;
|
|
property Items[Index: Integer]: PAnsiChar read GetItem; default;
|
|
end;
|
|
|
|
TdxCheckCompoundPatternTable = class(TdxSpellCheckerDataLinkedTable)
|
|
private
|
|
FIsSimplified: Boolean;
|
|
procedure ExtractCondition(APattern: PAnsiChar; var ACondition: Word);
|
|
function GetData: PdxCompoundForbidPatternArray;
|
|
function GetItem(Index: Integer): TdxCompoundForbidPattern;
|
|
protected
|
|
function AddDataPiece(const APiece: PAnsiChar; ADataIndex,
|
|
APieceIndex: Integer): Boolean; override;
|
|
procedure FreeDataItems; override;
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function GetDataItemSize: Integer; override;
|
|
function GetPieceQuantity: Integer; override;
|
|
procedure InitializeItem(Index: Integer); override;
|
|
public
|
|
property Data: PdxCompoundForbidPatternArray read GetData;
|
|
property IsSimplified: Boolean read FIsSimplified;
|
|
property Items[Index: Integer]: TdxCompoundForbidPattern read GetItem; default;
|
|
end;
|
|
|
|
TdxCompoundRuleTable = class(TdxSpellCheckerDataLinkedTable)
|
|
private
|
|
function GetData: PdxCompoundFlagArray;
|
|
function GetItem(Index: Integer): TdxCompoundFlag;
|
|
function ParseFlags(APiece: PAnsiChar; AIndex: Integer): Boolean;
|
|
protected
|
|
function AddDataPiece(const APiece: PAnsiChar; ADataIndex,
|
|
APieceIndex: Integer): Boolean; override;
|
|
procedure FreeDataItems; override;
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function GetDataItemSize: Integer; override;
|
|
function GetPieceQuantity: Integer; override;
|
|
procedure InitializeItem(Index: Integer); override;
|
|
public
|
|
property Data: PdxCompoundFlagArray read GetData;
|
|
property Items[Index: Integer]: TdxCompoundFlag read GetItem; default;
|
|
end;
|
|
|
|
TdxMapTable = class(TdxSpellCheckerDataTable)
|
|
private
|
|
function GetData: PdxMapArray;
|
|
function GetItem(Index: Integer): TdxMapTableItem;
|
|
protected
|
|
function AddDataPiece(const APiece: PAnsiChar; ADataIndex,
|
|
APieceIndex: Integer): Boolean; override;
|
|
procedure FreeDataItems; override;
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function GetDataItemSize: Integer; override;
|
|
function GetPieceQuantity: Integer; override;
|
|
procedure InitializeItem(Index: Integer); override;
|
|
public
|
|
property Data: PdxMapArray read GetData;
|
|
property Items[Index: Integer]: TdxMapTableItem read GetItem; default;
|
|
end;
|
|
|
|
TdxReplaceTable = class(TdxSpellCheckerDataTable)
|
|
private
|
|
function GetData: PdxReplaceArray;
|
|
function GetItem(Index: Integer): TdxReplaceTableItem;
|
|
protected
|
|
function AddDataPiece(const APiece: PAnsiChar; ADataIndex,
|
|
APieceIndex: Integer): Boolean; override;
|
|
procedure FreeDataItems; override;
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function GetDataItemSize: Integer; override;
|
|
function GetPieceQuantity: Integer; override;
|
|
procedure InitializeItem(Index: Integer); override;
|
|
public
|
|
property Data: PdxReplaceArray read GetData;
|
|
property Items[Index: Integer]: TdxReplaceTableItem read GetItem; default;
|
|
end;
|
|
|
|
TdxSortedReplaceTable = class(TdxReplaceTable)
|
|
private
|
|
function near1(const Aword: PAnsiChar): Integer;
|
|
function match(const Aword: PAnsiChar; n: Integer): Integer;
|
|
procedure Sort(AIndex: Integer);
|
|
protected
|
|
function AddDataPiece(const APiece: PAnsiChar; ADataIndex,
|
|
APieceIndex: Integer): Boolean; override;
|
|
public
|
|
function conv(const Aword: PAnsiChar; dest: PAnsiChar): Integer;
|
|
end;
|
|
|
|
TdxAffix = class
|
|
protected
|
|
FAffixManager: TdxHunspellAffixManager;
|
|
FAppendString: PAnsiChar;
|
|
FStripString: PAnsiChar;
|
|
FAppendStringLength: Byte;
|
|
FStripStringLength: Byte;
|
|
FConditionLength: ShortInt;
|
|
FOptions: ShortInt;
|
|
FFlag: Word;
|
|
FMorphologicalDescription: PAnsiChar;
|
|
FCompatibleFlags: TdxHunspellFlags;
|
|
FConditions: PdxAffixCondition;
|
|
FNext: TdxAffix;
|
|
FNextSimilar: TdxAffix;
|
|
FNextDifferent: TdxAffix;
|
|
FNextByFlag: TdxAffix;
|
|
|
|
function GetAppendString: PAnsiChar; virtual;
|
|
function GetPrefixSuffixUnion: Boolean;
|
|
protected
|
|
function CanUseInCompoundWordPart(ACompoundWordPart: TdxCompoundWordPart): Boolean; virtual; abstract;
|
|
function GetNextConditionChar(AConditionCursor: PAnsiChar): PAnsiChar;
|
|
function IsCompatibleWithFlag(AFlag: Word; CompatibleIfNull: Boolean = False): Boolean;
|
|
function IsPrefixSuffixUnion(AOptions: ShortInt): Boolean;
|
|
function IsWithoutAffixWordLengthCorrect(ALengthWithoutAffix: Integer): Boolean;
|
|
procedure SearchConditionGroupEnd(var AConditionCursor: PAnsiChar);
|
|
public
|
|
constructor Create(AAffixManager: TdxHunspellAffixManager;
|
|
AAffixItem: PdxAffixItem; AFlag: Word; AOptions: ShortInt);
|
|
destructor Destroy; override;
|
|
function CanUseInSimpleWordsOrIsFogemorpheme(ACompoundWordPart: TdxCompoundWordPart): Boolean;
|
|
function CanUseInTheMiddleOfCompoundWords(ACompoundWordPart: TdxCompoundWordPart): Boolean;
|
|
function IsCircumfix: Boolean;
|
|
|
|
property AffixManager: TdxHunspellAffixManager read FAffixManager;
|
|
property AppendString: PAnsiChar read GetAppendString;
|
|
property AppendStringLength: Byte read FAppendStringLength write FAppendStringLength;
|
|
property CompatibleFlags: TdxHunspellFlags read FCompatibleFlags write FCompatibleFlags;
|
|
property Flag: Word read FFlag;
|
|
property MorphologicalDescription: PAnsiChar read FMorphologicalDescription;
|
|
property Options: ShortInt read FOptions;
|
|
property PrefixSuffixUnion: Boolean read GetPrefixSuffixUnion;
|
|
|
|
property Next: TdxAffix read FNext write FNext;
|
|
property NextSimilar: TdxAffix read FNextSimilar write FNextSimilar;
|
|
property NextDifferent: TdxAffix read FNextDifferent write FNextDifferent;
|
|
property NextByFlag: TdxAffix read FNextByFlag write FNextByFlag;
|
|
end;
|
|
|
|
TdxSuffix = class;
|
|
|
|
TdxPrefix = class(TdxAffix)
|
|
protected
|
|
function CanUseInCompoundWordPart(ACompoundWordPart: TdxCompoundWordPart): Boolean; override;
|
|
public
|
|
function CheckWord(const AWord: PAnsiChar; AWordLength: Integer; var ATakenSuffix: TdxSuffix;
|
|
ACompoundWordPart: TdxCompoundWordPart; const ACompoundPartFlag: Word = NullFlag): TdxHunspellWordItem;
|
|
function MakeInitialWordFormAndProcessTwoSuffixCheck(const AWord: PAnsiChar; AWordLength: Integer;
|
|
var ATakenSuffix: TdxSuffix; ACompoundWordPart: TdxCompoundWordPart;
|
|
const ACompoundPartFlag: Word = NullFlag): TdxHunspellWordItem;
|
|
function IsWordSuitableToCondition(AWord: PAnsiChar): Boolean;
|
|
end;
|
|
|
|
TdxSuffix = class(TdxAffix)
|
|
private
|
|
FReverseAppendString: PAnsiChar;
|
|
l_morph: TdxSuffix; //TODO: Remove
|
|
r_morph: TdxSuffix;
|
|
eq_morph: TdxSuffix;
|
|
protected
|
|
function CanUseInCompoundWordPart(ACompoundWordPart: TdxCompoundWordPart): Boolean; override;
|
|
function GetAppendString: PAnsiChar; override;
|
|
public
|
|
constructor Create(AAffixManager: TdxHunspellAffixManager;
|
|
AAffixItem: PdxAffixItem; AFlag: Word; AOptions: ShortInt);
|
|
destructor Destroy; override;
|
|
function CheckWord(const AWord: PAnsiChar; AWordLength, AOptions: Integer;
|
|
APrefix: TdxPrefix; wlst: PPAnsiChar; maxSug: Integer; ns: PInteger;
|
|
const ACompatibleFlag: Word = NullFlag; const ACompoundPartFlag: Word = NullFlag; const AIncompatibleFlag: Word = NullFlag): TdxHunspellWordItem;
|
|
function MakeInitialWordFormAndProcessSuffixCheck(const AWord: PAnsiChar;
|
|
AWordLength, AOptions: Integer; APrefix: TdxPrefix; var ATakenSuffix: TdxSuffix;
|
|
const ACompoundPartFlag: Word = 0): TdxHunspellWordItem;
|
|
function GetWordWithAffix(const AWord: PAnsiChar; AWordLength: Integer): PAnsiChar;
|
|
|
|
function getLM: TdxSuffix;
|
|
function getRM: TdxSuffix;
|
|
function getEQM: TdxSuffix;
|
|
|
|
function IsWordSuitableToCondition(AWordEnd, AWordBegin: PAnsiChar): Boolean;
|
|
end;
|
|
|
|
TdxSuffixInfo = record
|
|
Flag: Word;
|
|
AppendString: PAnsiChar;
|
|
end;
|
|
|
|
TdxHunspellAffixManager = class
|
|
private
|
|
cpdvowels_utf16: PWideChar;
|
|
cpdvowels_utf16_len: Integer;
|
|
FAffixFilePath: string;
|
|
FBreakTable: TdxBreakTable;
|
|
FCheckCompoundCase: Boolean;
|
|
FCheckCompoundDup: Boolean;
|
|
FCheckCompoundPatternTable: TdxCheckCompoundPatternTable;
|
|
FCheckCompoundRep: Boolean;
|
|
FCheckCompoundTriple: Boolean;
|
|
FCheckSharps: Integer;
|
|
FCircumfix: Word;
|
|
FCodePage: Cardinal;
|
|
FCompatibleFlags: TAffixManagerFlagArray;
|
|
FCompatibleFlagsExist: Boolean;
|
|
FComplexPrefixes: Boolean;
|
|
FCompoundBegin: Word;
|
|
FCompoundEnd: Word;
|
|
FCompoundFlag: Word;
|
|
FCompoundForbidFlag: Word;
|
|
FCompoundMiddle: Word;
|
|
FCompoundPartMin: Integer;
|
|
FCompoundPermitFlag: Word;
|
|
FCompoundRoot: Word;
|
|
FCompoundRuleTable: TdxCompoundRuleTable;
|
|
FCompoundVowels: PAnsiChar;
|
|
FCompoundWordMax: Integer;
|
|
FExistentAffixFlags: TdxExistentAffixFlags;
|
|
FForbiddenWord: Word;
|
|
FFullStrip: Boolean;
|
|
FIgnore: PAnsiChar;
|
|
FInputReplaceTable: TdxSortedReplaceTable;
|
|
FIsExistentAffixFlagsInitialized: Boolean;
|
|
FIsUTF8: Boolean;
|
|
FKeepCase: Word;
|
|
FLanguage: Integer;
|
|
FLemmaPresent: Word;
|
|
FMapTable: TdxMapTable;
|
|
FMaxCompoundSyllable: Integer;
|
|
FMaxngramsugs: Integer;
|
|
FNeedAffix: Word;
|
|
FNoSplitSugs: Boolean;
|
|
FNoSuggest: Word;
|
|
FOnlyInCompound: Word;
|
|
FOutputReplaceTable: TdxSortedReplaceTable;
|
|
FPrefixTableArrangedByAppendString: TAffixTable;
|
|
FPrefixTableIndexedByFlag: TAffixTable;
|
|
FReplaceTable: TdxReplaceTable;
|
|
FSavedSuffixInfo: TdxSuffixInfo;
|
|
FSimplifiedTriple: Boolean;
|
|
FSubstandard: Word;
|
|
FSuffixTableArrangedByAppendString: TAffixTable;
|
|
FSuffixTableIndexedByFlag: TAffixTable;
|
|
FSugsWithDots: Boolean;
|
|
FSyllableNum: PAnsiChar;
|
|
FTryChars: PAnsiChar;
|
|
FVersion: PAnsiChar;
|
|
FWordBaseManager: TdxHunspellWordBaseManager;
|
|
ignorechars_utf16: PWord;
|
|
ignorechars_utf16_len: Integer;
|
|
FIsHungarian: Boolean;
|
|
wordchars_utf16: PWord;
|
|
wordchars_utf16_len: Integer;
|
|
function DoAffixParsing(ALine: PAnsiChar; AAffixFileManager: TdxHunspellReader; AAffixType: TdxAffixType): Boolean;
|
|
function ParseFile(const AFileName: string): Integer;
|
|
function ParseCompoundSyllable(ALine: PAnsiChar; AAffixFileManager: TdxHunspellReader): Boolean;
|
|
function ParseRep(ALine: PAnsiChar; AAffixFileManager: TdxHunspellReader): Boolean;
|
|
function ParseAffix(ALine: PAnsiChar; const IsPrefix: Boolean; AAffixFileManager: TdxHunspellReader; AExistentAffixFlags: TdxExistentAffixFlags): Boolean;
|
|
|
|
function AreAffixesBothCircumfixesOrNot(APrefix, ASuffix: TdxAffix): Boolean;
|
|
function CanBeFirstPartInCompoundWord(AWordBaseItem: TdxHunspellWordItem; AWordPartIndex: Cardinal): Boolean;
|
|
procedure CompoundRootCheck(AWordBaseItem: TdxHunspellWordItem; var AWordPartIndex: SmallInt);
|
|
function IsForbiddenOrNoSuggestWord(AWordBaseItem: TdxHunspellWordItem; ASuggest: Boolean): Boolean;
|
|
function IsWordPartSuitsCheckCompoundPatternTable(AWordBaseItem: TdxHunspellWordItem; ATableIndex: Integer; AIsFirstWordPart: Boolean): Boolean;
|
|
function IsWordPartSuitsCompoundFlags(AWordBaseItem: TdxHunspellWordItem; AWordPartIndex: SmallInt; AIsFirstWordPart: Boolean; words: PdxHunspellWordBaseTable): Boolean;
|
|
function IsTripleLettersExistAndForbid(AWord: PAnsiChar; AJoint: Cardinal): Boolean;
|
|
function UseWithAffixOnly(AWordBaseItem: TdxHunspellWordItem): Boolean;
|
|
|
|
function HungarianCheck(AWordBaseItem: TdxHunspellWordItem; hu_mov_rule: Boolean): Boolean;
|
|
function HungarianCheck2(var AWordBaseItem: TdxHunspellWordItem; AInitialWordForm: TWordFormArray;
|
|
ACompoundWordJoint: Integer; hu_mov_rule: Boolean;
|
|
var ATakenPrefix: TdxPrefix; var ATakenSuffix: TdxSuffix): Boolean;
|
|
|
|
procedure BuildAffixTree(AAffix: TdxAffix; var AAffixTableArrangedByAppendString: TAffixTable;
|
|
var AAffixTableIndexedByFlag: TAffixTable);
|
|
function ProcessSuffixOrPrefixCheck(const AWord: PAnsiChar; AWordLength: Integer;
|
|
ACompoundPartFlag: Word; ACompoundWordPart: TdxCompoundWordPart; var
|
|
AWordBaseTableItem: TdxHunspellWordItem; var ATakenPrefix: TdxPrefix; var ATakenSuffix: TdxSuffix): Boolean;
|
|
procedure LinkAffixesIntoSubsets(AAffixTableArrangedByAppendString: TAffixTable);
|
|
function OrderAffixTree(AAffix, ANextAffix: TdxAffix): TdxAffix;
|
|
procedure AffixTreeToList(var ATable: TAffixTable);
|
|
function GetIsCompoundWordsAvailable: Boolean;
|
|
function GetParseClasses: TObjectList;
|
|
procedure SetLanguage(Value: Integer);
|
|
protected
|
|
property FullStrip: Boolean read FFullStrip;
|
|
public
|
|
constructor Create(const AAffixFilePath: string;
|
|
AWordBaseManager: TdxHunspellWordBaseManager);
|
|
destructor Destroy; override;
|
|
function AffixCheck(const AWord: PAnsiChar; AWordLength: Integer; var ATakenPrefix: TdxPrefix; var ATakenSuffix: TdxSuffix;
|
|
const ACompoundPartFlag: Word = 0; ACompoundWordPart: TdxCompoundWordPart = cwpNone): TdxHunspellWordItem;
|
|
function ProcessPrefixCheck(const AWord: PAnsiChar; AWordLength: Integer;
|
|
var ATakenPrefix: TdxPrefix; var ATakenSuffix: TdxSuffix;
|
|
ACompoundWordPart: TdxCompoundWordPart; const ACompoundPartFlag: Word = NullFlag): TdxHunspellWordItem;
|
|
function IsLeadingSubset(ASubset: PAnsiChar; ASet: PAnsiChar): Boolean; {$IFDEF DELPHI9} inline; {$ENDIF}
|
|
function IsTrailingReversedSubset(AReversedSubset: PAnsiChar; AEndOfSet: PAnsiChar; ASetLength: Integer): Boolean;
|
|
function ProcessPrefixWithSuffixesCheck(const AWord: PAnsiChar; AWordLength: Integer;
|
|
var ATakenPrefix: TdxPrefix; var ATakenSuffix: TdxSuffix; ACompoundWordPart: TdxCompoundWordPart;
|
|
const ACompoundPartFlag: Word = NullFlag): TdxHunspellWordItem;
|
|
function ProcessSuffixCheck(const AWord: PAnsiChar; AWordLength, AOptions: Integer;
|
|
APrefix: TdxPrefix; var ATakenSuffix: TdxSuffix; wlst: PPAnsiChar; maxSug: Integer; ns: PInteger;
|
|
const ACompatibleFlag: Word = NullFlag; const ACompoundPartFlag: Word = NullFlag;
|
|
ACompoundWordPart: TdxCompoundWordPart = cwpNone): TdxHunspellWordItem;
|
|
function ProcessTwoSuffixCheck(const AWord: PAnsiChar; AWordLength, AOptions: Integer;
|
|
APrefix: TdxPrefix; var ATakenSuffix: TdxSuffix; const ACompoundPartFlag: Word = NullFlag): TdxHunspellWordItem;
|
|
function GetSyllableCount(const AWord: PAnsiChar; AWordLength: Integer): SmallInt;
|
|
function IsSimpleWordWithReplacedCharacters(
|
|
const AWord: PAnsiChar; AWordLength: Integer; var ATakenPrefix: TdxPrefix; var ATakenSuffix: TdxSuffix): Boolean;
|
|
function IsForbiddenByCheckCompoundPattern(const AWord: PAnsiChar; AJoint: Integer;
|
|
AFirstPartWordBase, ASecondPartWordBase: TdxHunspellWordItem): Boolean;
|
|
function IsWordPartsSuitCompoundRule(var AWords: PdxHunspellWordBaseTable; AWordCount: SmallInt;
|
|
AWordBaseItem: TdxHunspellWordItem; ADefaultWords: PdxHunspellWordBaseTable; all: Boolean): Boolean;
|
|
function IsJointUpperCaseExistAndForbid(const AWord: PAnsiChar; AJoint: Integer): Boolean;
|
|
function CompoundWordWithReplacedCharactersExists(const AWord: PAnsiChar;
|
|
AWordLength: Integer; var ATakenPrefix: TdxPrefix; var ATakenSuffix: TdxSuffix): Boolean;
|
|
procedure GetCompoundWordJointRange(var ACompoundWordJointMin, ACompoundWordJointMax: Integer; const AWord: PAnsiChar; AWordLength: Integer);
|
|
function CompoundCheck(const AWord: PAnsiChar;
|
|
AWordPartIndex, ASyllableCount, AWordPartMaxCount, wnum: SmallInt; words: PdxHunspellWordBaseTable = nil;
|
|
hu_mov_rule: Boolean = False; ASuggest: Boolean = False): TdxHunspellWordItem;
|
|
function Lookup(const AWord: PAnsiChar): TdxHunspellWordItem;
|
|
function EncodeFlag(AFlag: Word): PAnsiChar;
|
|
procedure SetCompatibleFlags(AIndex: Integer; AValue: Boolean);
|
|
|
|
property BreakTable: TdxBreakTable read FBreakTable;
|
|
property CheckSharps: Integer read FCheckSharps;
|
|
property CodePage: Cardinal read FCodePage write FCodePage;
|
|
property CompatibleFlagsExist: Boolean read FCompatibleFlagsExist write FCompatibleFlagsExist;
|
|
property ComplexPrefixes: Boolean read FComplexPrefixes;
|
|
property CompoundFlag: Word read FCompoundFlag;
|
|
property ForbiddenWord: Word read FForbiddenWord;
|
|
property Ignore: PAnsiChar read FIgnore;
|
|
property InputReplaceTable: TdxSortedReplaceTable read FInputReplaceTable;
|
|
property IsCompoundWordsAvailable: Boolean read GetIsCompoundWordsAvailable;
|
|
property IsHungarian: Boolean read FIsHungarian;
|
|
property IsUTF8: Boolean read FIsUTF8;
|
|
property KeepCase: Word read FKeepCase;
|
|
property Language: Integer read FLanguage write SetLanguage;
|
|
property Maxngramsugs: Integer read FMaxngramsugs;
|
|
property NeedAffix: Word read FNeedAffix;
|
|
property OutputReplaceTable: TdxSortedReplaceTable read FOutputReplaceTable;
|
|
property OnlyInCompound: Word read FOnlyInCompound;
|
|
property TryChars: PAnsiChar read FTryChars;
|
|
end;
|
|
|
|
TAffixFileReader = class
|
|
protected
|
|
FAffixManager: TdxHunspellAffixManager;
|
|
function GetDataIdentifier: PAnsiChar; virtual; abstract;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; virtual; abstract;
|
|
function ParseFlag(ALine: PAnsiChar; var ADecodedFlag: Word; AReader: TdxHunspellReader): Boolean;
|
|
function ParseNumber(ALine: PAnsiChar; out ANumber: Integer): Boolean;
|
|
public
|
|
constructor Create(AAffixManager: TdxHunspellAffixManager);
|
|
end;
|
|
|
|
TTryReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TSetReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TComplexPrefixesReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TCompoundFlagReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TCompoundBeginReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TCompoundEndReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TCompoundMiddleReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TCompoundWordMaxReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TCompoundRootReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TCompoundPermitFlagReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TCompoundForbidFlagReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TCheckCompoundDupReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TCheckCompoundRepReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TCheckCompoundTripleReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TSimplifiedTripleReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TCheckCompoundCaseReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TNoSuggestReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TForbiddenWordReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TLemmaPresentReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TCircumfixReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TOnlyInCompoundReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TPseudoRootReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TNeedAffixReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TCompoundMinReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TCompoundSyllableReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TSyllableNumReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TWordCharsReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TIgnoreReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TRepReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TIConvReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TOConvReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TCheckCompoundPatternReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TCompoundRuleReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TMapReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TBreakReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TLangReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TVersionReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TNoSplitSugsReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TFullStripReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TSugsWithDotsReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TKeepCaseReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TSubStandardReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TCheckSharpsReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TPrefixReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
TSuffixReader = class(TAffixFileReader)
|
|
protected
|
|
function GetDataIdentifier: PAnsiChar; override;
|
|
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
dxSpellCheckerUtils;
|
|
|
|
constructor TdxHunspellAffixManager.Create(const AAffixFilePath: string;
|
|
AWordBaseManager: TdxHunspellWordBaseManager);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
FWordBaseManager := AWordBaseManager;
|
|
FForbiddenWord := ForbiddenWordFlag;
|
|
FCompoundWordMax := -1;
|
|
FCompoundPartMin := -1;
|
|
FMaxngramsugs := -1;
|
|
FBreakTable := TdxBreakTable.Create;
|
|
FCheckCompoundPatternTable := TdxCheckCompoundPatternTable.Create(FWordBaseManager, Self);
|
|
FCompoundRuleTable := TdxCompoundRuleTable.Create(FWordBaseManager, Self);
|
|
FInputReplaceTable := TdxSortedReplaceTable.Create('ICONV');
|
|
FOutputReplaceTable := TdxSortedReplaceTable.Create('OCONV');
|
|
FMapTable := TdxMapTable.Create;
|
|
FReplaceTable := TdxReplaceTable.Create;
|
|
|
|
for I := 0 to AffixTableSize - 1 do
|
|
begin
|
|
FPrefixTableArrangedByAppendString[I] := nil;
|
|
FSuffixTableArrangedByAppendString[I] := nil;
|
|
FPrefixTableIndexedByFlag[I] := nil;
|
|
FSuffixTableIndexedByFlag[I] := nil;
|
|
end;
|
|
|
|
for I := 0 to MaxFlagCount - 1 do
|
|
FCompatibleFlags[I] := False;
|
|
|
|
FAffixFilePath := AAffixFilePath;
|
|
ParseFile(AAffixFilePath);
|
|
|
|
if FCompoundPartMin = -1 then
|
|
FCompoundPartMin := DefaultCompoundPartLength;
|
|
end;
|
|
|
|
destructor TdxHunspellAffixManager.Destroy;
|
|
var
|
|
I: Integer;
|
|
AAffix, ANextAffix: TdxAffix;
|
|
begin
|
|
for I := 0 to AffixTableSize - 1 do
|
|
begin
|
|
FPrefixTableIndexedByFlag[I] := nil;
|
|
FSuffixTableIndexedByFlag[I] := nil;
|
|
AAffix := TdxPrefix(FPrefixTableArrangedByAppendString[I]);
|
|
while AAffix <> nil do
|
|
begin
|
|
ANextAffix := AAffix.Next;
|
|
AAffix.Free;
|
|
AAffix := ANextAffix;
|
|
end;
|
|
AAffix := TdxSuffix(FSuffixTableArrangedByAppendString[I]);
|
|
while AAffix <> nil do
|
|
begin
|
|
ANextAffix := AAffix.Next;
|
|
AAffix.Free;
|
|
AAffix := ANextAffix;
|
|
end;
|
|
FSuffixTableArrangedByAppendString[I] := nil;
|
|
end;
|
|
|
|
if FTryChars <> nil then
|
|
StrDispose(FTryChars);
|
|
FTryChars := nil;
|
|
|
|
FreeAndNil(FMapTable);
|
|
|
|
FreeAndNil(FBreakTable);
|
|
FreeAndNil(FReplaceTable);
|
|
FreeAndNil(FInputReplaceTable);
|
|
FreeAndNil(FOutputReplaceTable);
|
|
|
|
FreeAndNil(FCompoundRuleTable);
|
|
|
|
FreeAndNil(FCheckCompoundPatternTable);
|
|
|
|
FWordBaseManager := nil;
|
|
if FCompoundVowels <> nil then
|
|
StrDispose(FCompoundVowels);
|
|
if cpdvowels_utf16 <> nil then
|
|
FreeMem(cpdvowels_utf16, cpdvowels_utf16_len * SizeOf(WideChar));
|
|
StrDispose(FSyllableNum);
|
|
if wordchars_utf16 <> nil then
|
|
FreeMem(wordchars_utf16, wordchars_utf16_len * SizeOf(Word));
|
|
StrDispose(FIgnore);
|
|
if ignorechars_utf16 <> nil then
|
|
FreeMem(ignorechars_utf16, ignorechars_utf16_len * SizeOf(Word));
|
|
StrDispose(FVersion);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.DoAffixParsing(ALine: PAnsiChar; AAffixFileManager: TdxHunspellReader; AAffixType: TdxAffixType): Boolean;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := True;
|
|
if AAffixType <> atNone then
|
|
begin
|
|
if not FIsExistentAffixFlagsInitialized then
|
|
begin
|
|
for I := 0 to MaxFlagCount - 1 do
|
|
FExistentAffixFlags[I] := 0;
|
|
FIsExistentAffixFlagsInitialized := True;
|
|
end;
|
|
if ParseAffix(ALine, AAffixType = atPrefix, AAffixFileManager, FExistentAffixFlags) then
|
|
begin
|
|
AffixTreeToList(FPrefixTableArrangedByAppendString);
|
|
AffixTreeToList(FSuffixTableArrangedByAppendString);
|
|
Result := False;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.ParseFile(const AFileName: string): Integer;
|
|
var
|
|
ALineCursor, ADataIdentifier: PAnsiChar;
|
|
AIsFirstLine: Boolean;
|
|
AAffixReader: TdxHunspellReader;
|
|
AParseClasses: TObjectList;
|
|
I: Integer;
|
|
begin
|
|
Result := 0;
|
|
FIsExistentAffixFlagsInitialized := False;
|
|
AIsFirstLine := True;
|
|
AAffixReader := nil;
|
|
ALineCursor := nil;
|
|
|
|
AParseClasses := GetParseClasses;
|
|
try
|
|
AAffixReader := TdxHunspellReader.Create(AFileName);
|
|
if AAffixReader = nil then
|
|
begin
|
|
Result := 1;
|
|
Exit;
|
|
end;
|
|
|
|
ALineCursor := AAffixReader.getline;
|
|
while ALineCursor <> nil do
|
|
begin
|
|
RemoveCRLF(ALineCursor);
|
|
|
|
if AIsFirstLine then
|
|
begin
|
|
AIsFirstLine := False;
|
|
RemoveMark(ALineCursor);
|
|
end;
|
|
|
|
for I := 0 to AParseClasses.Count - 1 do
|
|
begin
|
|
ADataIdentifier := TAffixFileReader(AParseClasses.Items[I]).GetDataIdentifier;
|
|
if StrLComp(ALineCursor, ADataIdentifier, StrLen(ADataIdentifier)) = 0 then
|
|
TAffixFileReader(AParseClasses.Items[I]).Process(ALineCursor, AAffixReader);
|
|
end;
|
|
|
|
StrDispose(ALineCursor);
|
|
ALineCursor := AAffixReader.getline;
|
|
end;
|
|
finally
|
|
StrDispose(ALineCursor);
|
|
AAffixReader.Free;
|
|
AParseClasses.Free;
|
|
end;
|
|
|
|
AffixTreeToList(FPrefixTableArrangedByAppendString);
|
|
AffixTreeToList(FSuffixTableArrangedByAppendString);
|
|
|
|
LinkAffixesIntoSubsets(FPrefixTableArrangedByAppendString);
|
|
LinkAffixesIntoSubsets(FSuffixTableArrangedByAppendString);
|
|
|
|
end;
|
|
|
|
procedure TdxHunspellAffixManager.BuildAffixTree(AAffix: TdxAffix;
|
|
var AAffixTableArrangedByAppendString: TAffixTable; var AAffixTableIndexedByFlag: TAffixTable);
|
|
var
|
|
ACurrentItem, APreviousAffix: TdxAffix;
|
|
AAppendString: PAnsiChar;
|
|
AFlag, AFirstChar: Byte;
|
|
begin
|
|
AAppendString := AAffix.AppendString;
|
|
AFlag := AAffix.Flag;
|
|
|
|
ACurrentItem := AAffixTableIndexedByFlag[AFlag];
|
|
AAffix.NextByFlag := ACurrentItem;
|
|
AAffixTableIndexedByFlag[AFlag] := AAffix;
|
|
|
|
if StrLen(AAppendString) = 0 then
|
|
begin
|
|
ACurrentItem := AAffixTableArrangedByAppendString[0];
|
|
AAffix.Next := ACurrentItem;
|
|
AAffixTableArrangedByAppendString[0] := AAffix;
|
|
Exit;
|
|
end;
|
|
|
|
AAffix.NextSimilar := nil;
|
|
AAffix.NextDifferent := nil;
|
|
|
|
AFirstChar := Ord(AAppendString^);
|
|
ACurrentItem := AAffixTableArrangedByAppendString[AFirstChar];
|
|
|
|
if ACurrentItem = nil then
|
|
begin
|
|
AAffixTableArrangedByAppendString[AFirstChar] := AAffix;
|
|
Exit;
|
|
end;
|
|
|
|
while True do
|
|
begin
|
|
APreviousAffix := ACurrentItem;
|
|
if StrComp(AAffix.AppendString, ACurrentItem.AppendString) <= 0 then
|
|
begin
|
|
ACurrentItem := ACurrentItem.NextSimilar;
|
|
if ACurrentItem = nil then
|
|
begin
|
|
APreviousAffix.NextSimilar := AAffix;
|
|
Break;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
ACurrentItem := ACurrentItem.NextDifferent;
|
|
if ACurrentItem = nil then
|
|
begin
|
|
APreviousAffix.NextDifferent := AAffix;
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.ProcessSuffixOrPrefixCheck(const AWord: PAnsiChar; AWordLength: Integer;
|
|
ACompoundPartFlag: Word; ACompoundWordPart: TdxCompoundWordPart;
|
|
var AWordBaseTableItem: TdxHunspellWordItem; var ATakenPrefix: TdxPrefix;
|
|
var ATakenSuffix: TdxSuffix): Boolean;
|
|
begin
|
|
AWordBaseTableItem := ProcessSuffixCheck(AWord, AWordLength, 0, nil, ATakenSuffix,
|
|
nil, 0, nil, NullFlag, ACompoundPartFlag, ACompoundWordPart);
|
|
Result := AWordBaseTableItem <> nil;
|
|
if not Result then
|
|
begin
|
|
AWordBaseTableItem := ProcessPrefixCheck(AWord, AWordLength, ATakenPrefix,
|
|
ATakenSuffix, ACompoundWordPart, ACompoundPartFlag);
|
|
Result := AWordBaseTableItem <> nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxHunspellAffixManager.AffixTreeToList(var ATable: TAffixTable);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 1 to AffixTableSize - 1 do
|
|
ATable[I] := OrderAffixTree(ATable[I], nil);
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.OrderAffixTree(AAffix, ANextAffix: TdxAffix): TdxAffix;
|
|
begin
|
|
if AAffix <> nil then
|
|
begin
|
|
ANextAffix := OrderAffixTree(AAffix.NextDifferent, ANextAffix);
|
|
AAffix.Next := ANextAffix;
|
|
ANextAffix := OrderAffixTree(AAffix.NextSimilar, AAffix);
|
|
end;
|
|
Result := ANextAffix;
|
|
end;
|
|
|
|
procedure TdxHunspellAffixManager.LinkAffixesIntoSubsets(AAffixTableArrangedByAppendString: TAffixTable);
|
|
var
|
|
AAffix, ANextAffix, ALastAffixInChain: TdxAffix;
|
|
I: Integer;
|
|
begin
|
|
for I := 1 to AffixTableSize - 1 do
|
|
begin
|
|
AAffix := AAffixTableArrangedByAppendString[I];
|
|
while AAffix <> nil do
|
|
begin
|
|
ANextAffix := AAffix.Next;
|
|
while ANextAffix <> nil do
|
|
begin
|
|
if not IsLeadingSubset(AAffix.AppendString, ANextAffix.AppendString) then
|
|
Break;
|
|
ANextAffix := ANextAffix.Next;
|
|
end;
|
|
AAffix.NextDifferent := ANextAffix;
|
|
AAffix.NextSimilar := nil;
|
|
if (AAffix.Next <> nil) and IsLeadingSubset(AAffix.AppendString, AAffix.Next.AppendString) then
|
|
AAffix.NextSimilar := AAffix.Next;
|
|
AAffix := AAffix.Next;
|
|
end;
|
|
|
|
AAffix := AAffixTableArrangedByAppendString[I];
|
|
while AAffix <> nil do
|
|
begin
|
|
ANextAffix := AAffix.Next;
|
|
ALastAffixInChain := nil;
|
|
while ANextAffix <> nil do
|
|
begin
|
|
if not IsLeadingSubset(AAffix.AppendString, ANextAffix.AppendString) then
|
|
Break;
|
|
ALastAffixInChain := ANextAffix;
|
|
ANextAffix := ANextAffix.Next;
|
|
end;
|
|
if ALastAffixInChain <> nil then
|
|
ALastAffixInChain.NextDifferent := nil;
|
|
AAffix := AAffix.Next;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.IsLeadingSubset(ASubset: PAnsiChar; ASet: PAnsiChar): Boolean;
|
|
begin
|
|
while (ASubset^ in [ASet^, '.']) and (ASubset^ <> #0) do
|
|
begin
|
|
Inc(ASubset);
|
|
Inc(ASet);
|
|
end;
|
|
Result := ASubset^ = #0;
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.IsTrailingReversedSubset(AReversedSubset: PAnsiChar;
|
|
AEndOfSet: PAnsiChar; ASetLength: Integer): Boolean;
|
|
begin
|
|
while (ASetLength > 0) and (AReversedSubset^ <> #0) and
|
|
((AReversedSubset^ = AEndOfSet^) or (AReversedSubset^ = '.')) do
|
|
begin
|
|
Inc(AReversedSubset);
|
|
Dec(AEndOfSet);
|
|
Dec(ASetLength);
|
|
end;
|
|
Result := AReversedSubset^ = #0;
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.ProcessPrefixCheck(const AWord: PAnsiChar; AWordLength: Integer;
|
|
var ATakenPrefix: TdxPrefix; var ATakenSuffix: TdxSuffix; ACompoundWordPart: TdxCompoundWordPart;
|
|
const ACompoundPartFlag: Word): TdxHunspellWordItem;
|
|
var
|
|
APrefix: TdxPrefix;
|
|
begin
|
|
Result := nil;
|
|
|
|
ATakenPrefix := nil;
|
|
FSavedSuffixInfo.AppendString := nil;
|
|
|
|
APrefix := TdxPrefix(FPrefixTableArrangedByAppendString[0]);
|
|
while (APrefix <> nil) and (Result = nil) do
|
|
begin
|
|
if APrefix.CanUseInSimpleWordsOrIsFogemorpheme(ACompoundWordPart) and
|
|
APrefix.CanUseInTheMiddleOfCompoundWords(ACompoundWordPart) then
|
|
begin
|
|
Result := APrefix.CheckWord(AWord, AWordLength, ATakenSuffix, ACompoundWordPart, ACompoundPartFlag); //TODO: Extract block
|
|
if Result <> nil then
|
|
ATakenPrefix := APrefix;
|
|
end;
|
|
APrefix := TdxPrefix(APrefix.Next);
|
|
end;
|
|
|
|
if Result = nil then
|
|
begin
|
|
APrefix := TdxPrefix(FPrefixTableArrangedByAppendString[PByte(AWord)^]);
|
|
while (APrefix <> nil) and (Result = nil) do
|
|
begin
|
|
if IsLeadingSubset(APrefix.AppendString, AWord) then
|
|
begin
|
|
if APrefix.CanUseInSimpleWordsOrIsFogemorpheme(ACompoundWordPart) and
|
|
APrefix.CanUseInTheMiddleOfCompoundWords(ACompoundWordPart) then
|
|
begin
|
|
Result := APrefix.CheckWord(AWord, AWordLength, ATakenSuffix, ACompoundWordPart, ACompoundPartFlag); //TODO: Extract block
|
|
if Result <> nil then
|
|
ATakenPrefix := APrefix;
|
|
end;
|
|
APrefix := TdxPrefix(APrefix.NextSimilar);
|
|
end
|
|
else
|
|
APrefix := TdxPrefix(APrefix.NextDifferent);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.ProcessPrefixWithSuffixesCheck(const AWord: PAnsiChar;
|
|
AWordLength: Integer; var ATakenPrefix: TdxPrefix; var ATakenSuffix: TdxSuffix;
|
|
ACompoundWordPart: TdxCompoundWordPart; const ACompoundPartFlag: Word): TdxHunspellWordItem;
|
|
var
|
|
APrefix: TdxPrefix;
|
|
begin
|
|
Result := nil;
|
|
|
|
ATakenPrefix := nil;
|
|
FSavedSuffixInfo.AppendString := nil;
|
|
|
|
APrefix := TdxPrefix(FPrefixTableArrangedByAppendString[0]);
|
|
while (APrefix <> nil) and (Result = nil) do
|
|
begin
|
|
Result := APrefix.MakeInitialWordFormAndProcessTwoSuffixCheck(AWord,
|
|
AWordLength, ATakenSuffix, ACompoundWordPart, ACompoundPartFlag);
|
|
APrefix := TdxPrefix(APrefix.Next);
|
|
end;
|
|
|
|
if Result = nil then
|
|
begin
|
|
APrefix := TdxPrefix(FPrefixTableArrangedByAppendString[PByte(AWord)^]);
|
|
|
|
while (APrefix <> nil) and (Result = nil) do
|
|
begin
|
|
if IsLeadingSubset(APrefix.AppendString, AWord) then
|
|
begin
|
|
Result := APrefix.MakeInitialWordFormAndProcessTwoSuffixCheck(AWord,
|
|
AWordLength, ATakenSuffix, ACompoundWordPart, ACompoundPartFlag);
|
|
if Result <> nil then
|
|
ATakenPrefix := APrefix;
|
|
APrefix := TdxPrefix(APrefix.NextSimilar);
|
|
end
|
|
else
|
|
APrefix := TdxPrefix(APrefix.NextDifferent);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.IsSimpleWordWithReplacedCharacters(
|
|
const AWord: PAnsiChar; AWordLength: Integer; var ATakenPrefix: TdxPrefix;
|
|
var ATakenSuffix: TdxSuffix): Boolean;
|
|
var
|
|
AChangedWord: array [0..MaxLineLength - 1] of AnsiChar;
|
|
AWordCursor: PAnsiChar;
|
|
AReplaceLength, AInitialLength, I: Integer;
|
|
begin
|
|
Result := False;
|
|
if (AWordLength < 2) or (FReplaceTable.Count = 0) or not FCheckCompoundRep then
|
|
Exit;
|
|
|
|
for I := 0 to FReplaceTable.Count - 1 do
|
|
begin
|
|
AWordCursor := AWord;
|
|
AReplaceLength := StrLen(FReplaceTable[I].Replacement);
|
|
AInitialLength := StrLen(FReplaceTable[I].Initial);
|
|
AWordCursor := StrPos(AWordCursor, FReplaceTable[I].Initial);
|
|
while AWordCursor <> nil do
|
|
begin
|
|
StrCopy(AChangedWord, AWord);
|
|
if AWordCursor - AWord + AReplaceLength +
|
|
Integer(StrLen(AWordCursor + AInitialLength)) > MaxLineLength then
|
|
Break;
|
|
StrCopy(AChangedWord + (AWordCursor - AWord), FReplaceTable[I].Replacement);
|
|
StrCopy(AChangedWord + (AWordCursor - AWord) + AReplaceLength,
|
|
AWordCursor + AInitialLength);
|
|
if CompoundWordWithReplacedCharactersExists(AChangedWord,
|
|
strlen(AChangedWord), ATakenPrefix, ATakenSuffix) then
|
|
begin
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
Inc(AWordCursor);
|
|
AWordCursor := StrPos(AWordCursor, FReplaceTable[I].Initial);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.IsForbiddenByCheckCompoundPattern(const AWord: PAnsiChar;
|
|
AJoint: Integer; AFirstPartWordBase, ASecondPartWordBase: TdxHunspellWordItem): Boolean;
|
|
var
|
|
ALength, I: Integer;
|
|
begin
|
|
Result := False;
|
|
for I := 0 to FCheckCompoundPatternTable.Count - 1 do
|
|
begin
|
|
ALength := StrLen(FCheckCompoundPatternTable[I].Pattern);
|
|
if IsLeadingSubset(FCheckCompoundPatternTable[I].Pattern2, AWord + AJoint) and
|
|
((AFirstPartWordBase = nil) or (FCheckCompoundPatternTable[I].Condition = 0) or
|
|
AFirstPartWordBase.IsCompatibleWithFlag(FCheckCompoundPatternTable[I].Condition)) and
|
|
((ASecondPartWordBase = nil) or (FCheckCompoundPatternTable[I].Condition2 = 0) or
|
|
ASecondPartWordBase.IsCompatibleWithFlag(FCheckCompoundPatternTable[I].Condition2)) and
|
|
(ALength <> 0) and (AJoint > ALength) and
|
|
(StrLComp(AWord + AJoint - ALength, FCheckCompoundPatternTable[I].Pattern, ALength) = 0) then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.IsJointUpperCaseExistAndForbid(const AWord: PAnsiChar; AJoint: Integer): Boolean;
|
|
var
|
|
A, B: AnsiChar;
|
|
begin
|
|
Result := False;
|
|
begin
|
|
A := (AWord + AJoint - 1)^;
|
|
B := (AWord + AJoint)^;
|
|
if (IsUpCase(A) or IsUpCase(B)) and (A <> '-') and (B <> '-') then
|
|
Result := FCheckCompoundCase;
|
|
end;
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.IsWordPartsSuitCompoundRule(var AWords: PdxHunspellWordBaseTable;
|
|
AWordCount: SmallInt; AWordBaseItem: TdxHunspellWordItem;
|
|
ADefaultWords: PdxHunspellWordBaseTable; all: Boolean): Boolean;
|
|
type
|
|
TBackTrackingItem = record
|
|
MetacharacterPosition: SmallInt;
|
|
WordsIndex: SmallInt;
|
|
MatchedCharactersCount: Integer;
|
|
end;
|
|
var
|
|
ABackTrackingTable: array [0..MaxWordLength - 1] of TBackTrackingItem;
|
|
ABackTrackingIndex, AOldBackTrackingIndex, AFlagCursor, AFlagCursor2,
|
|
AMetacharacterPointer, AWordIndex: SmallInt;
|
|
I, J, AWordIndexMax: Integer;
|
|
AIsWordBaseItemCompatibleWithCompoundRule, AIsAllWordsCompatibleWithCompoundRule,
|
|
AIsWordsInitialized: Boolean;
|
|
AFlag: Word;
|
|
begin
|
|
Result := False;
|
|
|
|
if (AWordBaseItem.AffixFlags.Length = 0) or
|
|
(AWords = nil) and (ADefaultWords = nil) then
|
|
Exit;
|
|
|
|
AIsWordBaseItemCompatibleWithCompoundRule := False;
|
|
for I := 0 to FCompoundRuleTable.Count - 1 do
|
|
for J := 0 to FCompoundRuleTable[I].Length - 1 do
|
|
begin
|
|
AFlag := FCompoundRuleTable[I].Pattern[J];
|
|
if (AFlag <> Ord('*')) and (AFlag <> Ord('?')) and
|
|
AWordBaseItem.IsCompatibleWithFlag(AFlag) then
|
|
AIsWordBaseItemCompatibleWithCompoundRule := True;
|
|
end;
|
|
|
|
if AIsWordBaseItemCompatibleWithCompoundRule then
|
|
begin
|
|
AIsWordsInitialized := False;
|
|
if AWords = nil then
|
|
begin
|
|
AIsWordsInitialized := True;
|
|
AWords := ADefaultWords;
|
|
end;
|
|
AWords[AWordCount] := AWordBaseItem;
|
|
|
|
ABackTrackingIndex := 0;
|
|
I := 0;
|
|
while (I < FCompoundRuleTable.Count) and not Result do
|
|
begin
|
|
AFlagCursor := 0;
|
|
AWordIndex := 0;
|
|
AIsWordBaseItemCompatibleWithCompoundRule := True;
|
|
AIsAllWordsCompatibleWithCompoundRule := True;
|
|
repeat
|
|
while (AFlagCursor < FCompoundRuleTable[I].Length) and (AWordIndex <= AWordCount) do
|
|
begin
|
|
AMetacharacterPointer := AFlagCursor + 1;
|
|
AFlag := 0;
|
|
if AMetacharacterPointer < FCompoundRuleTable[I].Length then
|
|
AFlag := FCompoundRuleTable[I].Pattern[AMetacharacterPointer];
|
|
if (AMetacharacterPointer < FCompoundRuleTable[I].Length) and
|
|
((AFlag = Ord('*')) or (AFlag = Ord('?'))) then
|
|
begin
|
|
AWordIndexMax := IfThen(AFlag = Ord('?'), AWordIndex, AWordCount);
|
|
AIsAllWordsCompatibleWithCompoundRule := True;
|
|
Inc(AFlagCursor, 2);
|
|
ABackTrackingTable[ABackTrackingIndex].MetacharacterPosition := AFlagCursor;
|
|
ABackTrackingTable[ABackTrackingIndex].WordsIndex := AWordIndex;
|
|
while AWordIndex <= AWordIndexMax do
|
|
begin
|
|
if not AWords[AWordIndex].IsCompatibleWithFlag(FCompoundRuleTable[I].Pattern[AFlagCursor - 2]) then
|
|
begin
|
|
AIsAllWordsCompatibleWithCompoundRule := False;
|
|
Break;
|
|
end;
|
|
Inc(AWordIndex);
|
|
end;
|
|
if AWordIndex <= AWordCount then
|
|
AIsAllWordsCompatibleWithCompoundRule := False;
|
|
ABackTrackingTable[ABackTrackingIndex].MatchedCharactersCount :=
|
|
AWordIndex - ABackTrackingTable[ABackTrackingIndex].WordsIndex;
|
|
if ABackTrackingTable[ABackTrackingIndex].MatchedCharactersCount > 0 then
|
|
Inc(ABackTrackingIndex);
|
|
if AIsAllWordsCompatibleWithCompoundRule then
|
|
Break;
|
|
end
|
|
else
|
|
begin
|
|
AIsAllWordsCompatibleWithCompoundRule := True;
|
|
if (AWords[AWordIndex] = nil) or
|
|
not AWords[AWordIndex].IsCompatibleWithFlag(FCompoundRuleTable[I].Pattern[AFlagCursor]) then
|
|
begin
|
|
AIsWordBaseItemCompatibleWithCompoundRule := False;
|
|
Break;
|
|
end;
|
|
Inc(AFlagCursor);
|
|
Inc(AWordIndex);
|
|
if (FCompoundRuleTable[I].Length = AFlagCursor) and not(AWordIndex > AWordCount) then
|
|
AIsWordBaseItemCompatibleWithCompoundRule := False;
|
|
end;
|
|
end;
|
|
if AIsWordBaseItemCompatibleWithCompoundRule and AIsAllWordsCompatibleWithCompoundRule then
|
|
begin
|
|
AFlagCursor2 := AFlagCursor;
|
|
while (AFlagCursor2 + 1 < FCompoundRuleTable[I].Length) and
|
|
((FCompoundRuleTable[I].Pattern[AFlagCursor2 + 1] = Ord('*')) or
|
|
(FCompoundRuleTable[I].Pattern[AFlagCursor2 + 1] = Ord('?'))) do
|
|
Inc(AFlagCursor2, 2);
|
|
if FCompoundRuleTable[I].Length <= AFlagCursor2 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
end;
|
|
if ABackTrackingIndex > 0 then
|
|
begin
|
|
repeat
|
|
AIsWordBaseItemCompatibleWithCompoundRule := True;
|
|
Dec(ABackTrackingTable[ABackTrackingIndex - 1].MatchedCharactersCount);
|
|
AFlagCursor := ABackTrackingTable[ABackTrackingIndex - 1].MetacharacterPosition;
|
|
AWordIndex := ABackTrackingTable[ABackTrackingIndex - 1].WordsIndex +
|
|
ABackTrackingTable[ABackTrackingIndex - 1].MatchedCharactersCount;
|
|
AOldBackTrackingIndex := ABackTrackingIndex;
|
|
Dec(ABackTrackingIndex);
|
|
until not((ABackTrackingTable[AOldBackTrackingIndex - 1].MatchedCharactersCount < 0) and
|
|
(ABackTrackingIndex > 0));
|
|
if not(ABackTrackingTable[AOldBackTrackingIndex - 1].MatchedCharactersCount < 0) then
|
|
ABackTrackingIndex := AOldBackTrackingIndex;
|
|
end;
|
|
until ABackTrackingIndex = 0;
|
|
|
|
if AIsWordBaseItemCompatibleWithCompoundRule and AIsAllWordsCompatibleWithCompoundRule and (not all or (FCompoundRuleTable[I].Length <= AFlagCursor)) then
|
|
Result := True;
|
|
|
|
while AIsWordBaseItemCompatibleWithCompoundRule and AIsAllWordsCompatibleWithCompoundRule and
|
|
(AFlagCursor + 1 < FCompoundRuleTable[I].Length) and
|
|
((FCompoundRuleTable[I].Pattern[AFlagCursor + 1] = Ord('*')) or (FCompoundRuleTable[I].Pattern[AFlagCursor + 1] = Ord('?'))) do
|
|
Inc(AFlagCursor, 2);
|
|
if AIsWordBaseItemCompatibleWithCompoundRule and AIsAllWordsCompatibleWithCompoundRule and
|
|
(FCompoundRuleTable[I].Length <= AFlagCursor) then
|
|
Result := True;
|
|
|
|
Inc(I);
|
|
end;
|
|
if not Result then
|
|
begin
|
|
AWords[AWordCount] := nil;
|
|
if AIsWordsInitialized then
|
|
AWords := nil;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.CompoundWordWithReplacedCharactersExists(
|
|
const AWord: PAnsiChar; AWordLength: Integer; var ATakenPrefix: TdxPrefix; var ATakenSuffix: TdxSuffix): Boolean;
|
|
begin
|
|
Result := True;
|
|
if Lookup(AWord) = nil then
|
|
if AffixCheck(AWord, AWordLength, ATakenPrefix, ATakenSuffix) = nil then
|
|
Result := False;
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.GetSyllableCount(const AWord: PAnsiChar; AWordLength: Integer): SmallInt;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := 0;
|
|
if FMaxCompoundSyllable = 0 then
|
|
Exit;
|
|
|
|
if not FIsUTF8 then
|
|
begin
|
|
for I := 0 to AWordLength - 1 do
|
|
if StrScan(FCompoundVowels, (AWord + I)^) <> nil then
|
|
Inc(Result);
|
|
end
|
|
else
|
|
//TODO:
|
|
;
|
|
end;
|
|
|
|
procedure TdxHunspellAffixManager.GetCompoundWordJointRange(var ACompoundWordJointMin,
|
|
ACompoundWordJointMax: Integer; const AWord: PAnsiChar; AWordLength: Integer);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if FIsUTF8 then
|
|
begin
|
|
ACompoundWordJointMin := 0;
|
|
I := 0;
|
|
while (I < FCompoundPartMin) and ((AWord + ACompoundWordJointMin) <> nil) do
|
|
begin
|
|
Inc(ACompoundWordJointMin);
|
|
while Ord((AWord + ACompoundWordJointMin)^) and $c0 = $80 do
|
|
Inc(ACompoundWordJointMin);
|
|
Inc(I);
|
|
end;
|
|
ACompoundWordJointMax := AWordLength;
|
|
I := 0;
|
|
while (I < FCompoundPartMin - 1) and (ACompoundWordJointMax <> 0) do
|
|
begin
|
|
Dec(ACompoundWordJointMax);
|
|
while Ord((AWord + ACompoundWordJointMax)^) and $c0 = $80 do
|
|
Dec(ACompoundWordJointMax);
|
|
Inc(I);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
ACompoundWordJointMin := FCompoundPartMin;
|
|
ACompoundWordJointMax := AWordLength - FCompoundPartMin + 1;
|
|
end;
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.CompoundCheck(const AWord: PAnsiChar;
|
|
AWordPartIndex, ASyllableCount, AWordPartMaxCount, wnum: SmallInt; words: PdxHunspellWordBaseTable = nil;
|
|
hu_mov_rule: Boolean = False; ASuggest: Boolean = False): TdxHunspellWordItem;
|
|
var
|
|
ACompoundWordJoint, AWordLength, ACompoundWordJointMin, ACompoundWordJointMax,
|
|
ATableIndex, AInitialWordJoint: Integer;
|
|
ACheckedPrefix: Boolean;
|
|
ADoubleCharacter, ACheckWordWithoutTripleRemoving: Boolean;
|
|
ASyllableCountStore, ASyllableCountStore2, AWordPartIndexStore, AWordPartIndexStore2: SmallInt;
|
|
AWordBaseItem, AFirstPartWordBaseItem: TdxHunspellWordItem;
|
|
ACompoundRuleWords: array[0..MaxWordLength] of TdxHunspellWordItem;
|
|
AInitialWordForm: TWordFormArray;
|
|
AJointCharacter: AnsiChar;
|
|
ACompoundWordPart: TdxCompoundWordPart;
|
|
ATakenPrefix: TdxPrefix;
|
|
ATakenSuffix: TdxSuffix;
|
|
|
|
function CheckSimpleWordWithReplacedCharacters: TdxHunspellWordItem;
|
|
begin
|
|
if IsSimpleWordWithReplacedCharacters(AWord, AWordLength, ATakenPrefix, ATakenSuffix) then
|
|
Result := nil
|
|
else
|
|
Result := AFirstPartWordBaseItem;
|
|
end;
|
|
|
|
procedure HungarianSyllableProcess;
|
|
begin
|
|
if IsHungarian then
|
|
begin
|
|
Inc(ASyllableCount, GetSyllableCount(AInitialWordForm, AInitialWordJoint));
|
|
if (ATakenPrefix <> nil) and (GetSyllableCount(ATakenPrefix.AppendString, StrLen(ATakenPrefix.AppendString)) > 1) then
|
|
Inc(AWordPartIndex);
|
|
end;
|
|
end;
|
|
|
|
procedure HungarianDecreaseSyllableCount;
|
|
begin
|
|
if (AWordBaseItem <> nil) and IsHungarian and
|
|
AWordBaseItem.IsCompatibleWithFlag(Ord('I')) and
|
|
not AWordBaseItem.IsCompatibleWithFlag(Ord('J')) then
|
|
Dec(ASyllableCount);
|
|
end;
|
|
|
|
begin
|
|
Result := nil;
|
|
|
|
AWordLength := StrLen(AWord);
|
|
if IsSimpleWordWithReplacedCharacters(AWord, AWordLength, ATakenPrefix, ATakenSuffix) then
|
|
Exit;
|
|
|
|
AWordBaseItem := nil;
|
|
ADoubleCharacter := False;
|
|
ACheckWordWithoutTripleRemoving := False;
|
|
ATableIndex := 0;
|
|
|
|
GetCompoundWordJointRange(ACompoundWordJointMin, ACompoundWordJointMax, AWord, AWordLength);
|
|
StrCopy(AInitialWordForm, AWord);
|
|
ACompoundWordJoint := ACompoundWordJointMin;
|
|
while ACompoundWordJoint < ACompoundWordJointMax do
|
|
begin
|
|
AWordLength := StrLen(AWord);
|
|
GetCompoundWordJointRange(ACompoundWordJointMin, ACompoundWordJointMax, AWord, AWordLength);
|
|
StrCopy(AInitialWordForm, AWord);
|
|
|
|
ASyllableCountStore := ASyllableCount;
|
|
AWordPartIndexStore := AWordPartIndex;
|
|
ACheckedPrefix := False;
|
|
|
|
if IsUTF8 then
|
|
begin
|
|
//TODO:
|
|
end;
|
|
|
|
repeat
|
|
AInitialWordJoint := ACompoundWordJoint;
|
|
if ATableIndex > 0 then
|
|
begin
|
|
while (ATableIndex <= FCheckCompoundPatternTable.Count) and
|
|
((FCheckCompoundPatternTable[ATableIndex - 1].Pattern3 = nil) or
|
|
(StrLComp(AWord + ACompoundWordJoint, FCheckCompoundPatternTable[ATableIndex - 1].Pattern3,
|
|
StrLen(FCheckCompoundPatternTable[ATableIndex - 1].Pattern3)) <> 0)) do
|
|
Inc(ATableIndex);
|
|
|
|
if ATableIndex > FCheckCompoundPatternTable.Count then
|
|
Break;
|
|
StrCopy(AInitialWordForm + ACompoundWordJoint, FCheckCompoundPatternTable[ATableIndex - 1].Pattern);
|
|
AInitialWordJoint := ACompoundWordJoint;
|
|
Inc(AInitialWordJoint, StrLen(FCheckCompoundPatternTable[ATableIndex - 1].Pattern));
|
|
StrCopy(AInitialWordForm + AInitialWordJoint, FCheckCompoundPatternTable[ATableIndex - 1].Pattern2);
|
|
StrCopy(AInitialWordForm + AInitialWordJoint + StrLen(FCheckCompoundPatternTable[ATableIndex - 1].Pattern2),
|
|
AWord + ACompoundWordJoint + StrLen(FCheckCompoundPatternTable[ATableIndex - 1].Pattern3));
|
|
|
|
Inc(AWordLength, StrLen(FCheckCompoundPatternTable[ATableIndex - 1].Pattern) +
|
|
StrLen(FCheckCompoundPatternTable[ATableIndex - 1].Pattern2) -
|
|
StrLen(FCheckCompoundPatternTable[ATableIndex - 1].Pattern3));
|
|
GetCompoundWordJointRange(ACompoundWordJointMin, ACompoundWordJointMax,
|
|
AInitialWordForm, AWordLength);
|
|
|
|
ACompoundWordJointMax := AWordLength - FCompoundPartMin + 1; //TODO: Remove after UTF8 removing, because GetCompoundWordJointRange hes this line
|
|
end;
|
|
|
|
AJointCharacter := AInitialWordForm[AInitialWordJoint];
|
|
AInitialWordForm[AInitialWordJoint] := #0;
|
|
|
|
ATakenSuffix := nil;
|
|
ATakenPrefix := nil;
|
|
|
|
AWordBaseItem := Lookup(AInitialWordForm);
|
|
|
|
while (AWordBaseItem <> nil) and not hu_mov_rule and
|
|
(UseWithAffixOnly(AWordBaseItem) or
|
|
not ((IsWordPartSuitsCompoundFlags(AWordBaseItem, AWordPartIndex, True, words) or
|
|
((words <> nil) or (AWordPartIndex = 0)) and
|
|
IsWordPartsSuitCompoundRule(words, wnum, AWordBaseItem, @ACompoundRuleWords, False)) and
|
|
IsWordPartSuitsCheckCompoundPatternTable(AWordBaseItem, ATableIndex, True))) do
|
|
AWordBaseItem := AWordBaseItem.NextHomonym;
|
|
|
|
if AWordBaseItem = nil then
|
|
begin
|
|
ACompoundWordPart := cwpFirst;
|
|
if hu_mov_rule then
|
|
ACompoundWordPart := cwpOther;
|
|
|
|
if (FCompoundFlag <> 0) then
|
|
begin
|
|
AWordBaseItem := ProcessPrefixCheck(AInitialWordForm, AInitialWordJoint,
|
|
ATakenPrefix, ATakenSuffix, ACompoundWordPart, FCompoundFlag);
|
|
if AWordBaseItem = nil then
|
|
begin
|
|
AWordBaseItem := ProcessSuffixCheck(AInitialWordForm, AInitialWordJoint,
|
|
0, nil, ATakenSuffix, nil, 0, nil, NullFlag, FCompoundFlag, ACompoundWordPart);
|
|
if (AWordBaseItem <> nil) and not hu_mov_rule and
|
|
(((FCompoundForbidFlag <> 0) and ATakenSuffix.IsCompatibleWithFlag(FCompoundForbidFlag)) or
|
|
((FCompoundEnd <> 0) and ATakenSuffix.IsCompatibleWithFlag(FCompoundEnd))) then
|
|
AWordBaseItem := nil;
|
|
end;
|
|
end;
|
|
|
|
if (AWordBaseItem <> nil) or
|
|
(((AWordPartIndex = 0) and (FCompoundBegin <> 0) and
|
|
ProcessSuffixOrPrefixCheck(AInitialWordForm, AInitialWordJoint,
|
|
FCompoundBegin, ACompoundWordPart, AWordBaseItem, ATakenPrefix, ATakenSuffix)) or
|
|
((AWordPartIndex > 0) and (FCompoundMiddle <> 0) and
|
|
ProcessSuffixOrPrefixCheck(AInitialWordForm, AInitialWordJoint,
|
|
FCompoundMiddle, ACompoundWordPart, AWordBaseItem, ATakenPrefix, ATakenSuffix))) then
|
|
ACheckedPrefix := True;
|
|
end
|
|
else
|
|
if UseWithAffixOnly(AWordBaseItem) or
|
|
IsForbiddenOrNoSuggestWord(AWordBaseItem, ASuggest) then
|
|
begin
|
|
AInitialWordForm[AInitialWordJoint] := AJointCharacter;
|
|
Continue;
|
|
end;
|
|
|
|
if (AWordBaseItem <> nil) and not hu_mov_rule and
|
|
(((ATakenPrefix <> nil) and ATakenPrefix.IsCompatibleWithFlag(FCompoundForbidFlag)) or
|
|
((ATakenSuffix <> nil) and ATakenSuffix.IsCompatibleWithFlag(FCompoundForbidFlag))) then
|
|
AWordBaseItem := nil;
|
|
|
|
if (AWordBaseItem <> nil) and not ACheckedPrefix and (FCompoundEnd <> 0) and not hu_mov_rule and
|
|
(((ATakenPrefix <> nil) and ATakenPrefix.IsCompatibleWithFlag(FCompoundEnd)) or
|
|
((ATakenSuffix <> nil) and ATakenSuffix.IsCompatibleWithFlag(FCompoundEnd))) then
|
|
AWordBaseItem := nil;
|
|
|
|
if (AWordBaseItem <> nil) and not ACheckedPrefix and (AWordPartIndex = 0) and
|
|
(FCompoundMiddle <> 0) and not hu_mov_rule and
|
|
(((ATakenPrefix <> nil) and ATakenPrefix.IsCompatibleWithFlag(FCompoundMiddle)) or
|
|
((ATakenSuffix <> nil) and ATakenSuffix.IsCompatibleWithFlag(FCompoundMiddle))) then
|
|
AWordBaseItem := nil;
|
|
|
|
if IsForbiddenOrNoSuggestWord(AWordBaseItem, ASuggest) then
|
|
begin
|
|
Result := nil;
|
|
Exit;
|
|
end;
|
|
|
|
CompoundRootCheck(AWordBaseItem, AWordPartIndex);
|
|
|
|
if ((AWordBaseItem <> nil) and
|
|
(ACheckedPrefix or ((words <> nil) and (words[wnum] <> nil)) or
|
|
CanBeFirstPartInCompoundWord(AWordBaseItem, AWordPartIndexStore) or
|
|
HungarianCheck(AWordBaseItem, hu_mov_rule)) and
|
|
IsWordPartSuitsCheckCompoundPatternTable(AWordBaseItem, ATableIndex, True) and
|
|
not ((ATableIndex = 0) and (words = nil) and
|
|
(IsTripleLettersExistAndForbid(AWord, AInitialWordJoint) or
|
|
IsJointUpperCaseExistAndForbid(AWord, AInitialWordJoint)))) or
|
|
HungarianCheck2(AWordBaseItem, AInitialWordForm, ACompoundWordJoint, hu_mov_rule, ATakenPrefix, ATakenSuffix) then
|
|
begin
|
|
HungarianSyllableProcess;
|
|
|
|
// Second part of word
|
|
AFirstPartWordBaseItem := AWordBaseItem;
|
|
AInitialWordForm[AInitialWordJoint] := AJointCharacter;
|
|
|
|
repeat
|
|
if FSimplifiedTriple then
|
|
begin
|
|
if ADoubleCharacter then
|
|
begin
|
|
ACheckWordWithoutTripleRemoving := True;
|
|
Dec(AInitialWordJoint);
|
|
end
|
|
else
|
|
if (AInitialWordJoint > 2) and ((AWord + AInitialWordJoint - 1)^ = (AWord + AInitialWordJoint - 2)^) then
|
|
ADoubleCharacter := True;
|
|
end;
|
|
|
|
AWordBaseItem := Lookup(AInitialWordForm + AInitialWordJoint);
|
|
|
|
while (AWordBaseItem <> nil) and
|
|
(UseWithAffixOnly(AWordBaseItem) or
|
|
not ((IsWordPartSuitsCompoundFlags(AWordBaseItem, 0, False, words) or
|
|
IsWordPartsSuitCompoundRule(words, wnum + 1, AWordBaseItem, nil, True)) and
|
|
IsWordPartSuitsCheckCompoundPatternTable(AWordBaseItem, ATableIndex, False))) do
|
|
AWordBaseItem := AWordBaseItem.NextHomonym;
|
|
|
|
if (AWordBaseItem <> nil) and (words <> nil) and (words[wnum + 1] <> nil) then
|
|
begin
|
|
Result := AFirstPartWordBaseItem;
|
|
Exit;
|
|
end;
|
|
|
|
if IsForbiddenOrNoSuggestWord(AWordBaseItem, ASuggest) then
|
|
begin
|
|
Result := nil;
|
|
Exit;
|
|
end;
|
|
|
|
ASyllableCountStore2 := ASyllableCount;
|
|
AWordPartIndexStore2 := AWordPartIndex;
|
|
|
|
HungarianDecreaseSyllableCount;
|
|
|
|
CompoundRootCheck(AWordBaseItem, AWordPartIndex);
|
|
|
|
if (AWordBaseItem <> nil) and
|
|
(AWordBaseItem.IsCompatibleWithFlag(FCompoundFlag) or
|
|
AWordBaseItem.IsCompatibleWithFlag(FCompoundEnd)) and
|
|
(((FCompoundWordMax = -1) or (AWordPartIndex + 1 < FCompoundWordMax)) or
|
|
((FMaxCompoundSyllable <> 0) and
|
|
(ASyllableCount + GetSyllableCount(AWordBaseItem.WordBase, AWordBaseItem.clen) <= FMaxCompoundSyllable))) and
|
|
((ATableIndex <> 0) or
|
|
not IsForbiddenByCheckCompoundPattern(AWord, ACompoundWordJoint, AFirstPartWordBaseItem, AWordBaseItem)) and
|
|
(not FCheckCompoundDup or (AWordBaseItem <> AFirstPartWordBaseItem)) and
|
|
IsWordPartSuitsCheckCompoundPatternTable(AWordBaseItem, ATableIndex, False) then
|
|
begin
|
|
Result := AFirstPartWordBaseItem;
|
|
Exit;
|
|
end;
|
|
|
|
ASyllableCount := ASyllableCountStore2;
|
|
AWordPartIndex := AWordPartIndexStore2;
|
|
|
|
ATakenSuffix := nil;
|
|
FSavedSuffixInfo.Flag := NullFlag;
|
|
if FCompoundFlag <> 0 then
|
|
AWordBaseItem := AffixCheck(AWord + AInitialWordJoint, StrLen(AWord + AInitialWordJoint),
|
|
ATakenPrefix, ATakenSuffix, FCompoundFlag, cwpLast)
|
|
else
|
|
AWordBaseItem := nil;
|
|
if (AWordBaseItem = nil) and (FCompoundEnd <> 0) then
|
|
begin
|
|
ATakenSuffix := nil;
|
|
ATakenPrefix := nil;
|
|
AWordBaseItem := AffixCheck(AWord + AInitialWordJoint, StrLen(AWord + AInitialWordJoint),
|
|
ATakenPrefix, ATakenSuffix, FCompoundEnd, cwpLast);
|
|
end;
|
|
|
|
if (AWordBaseItem = nil) and (FCompoundRuleTable.Count <> 0) and (words <> nil) then
|
|
begin
|
|
AWordBaseItem := AffixCheck(AWord + AInitialWordJoint, StrLen(AWord + AInitialWordJoint),
|
|
ATakenPrefix, ATakenSuffix, 0, cwpLast);
|
|
if (AWordBaseItem <> nil) and IsWordPartsSuitCompoundRule(words, wnum + 1, AWordBaseItem, nil, True) then
|
|
begin
|
|
Result := AFirstPartWordBaseItem;
|
|
Exit;
|
|
end;
|
|
AWordBaseItem := nil;
|
|
end;
|
|
|
|
if (AWordBaseItem <> nil) and not ((ATableIndex = 0) or (FCheckCompoundPatternTable[ATableIndex - 1].Condition2 = NullFlag) or
|
|
AWordBaseItem.IsCompatibleWithFlag(FCheckCompoundPatternTable[ATableIndex - 1].Condition2)) then
|
|
AWordBaseItem := nil;
|
|
|
|
if (AWordBaseItem <> nil) and (ATableIndex = 0) and
|
|
IsForbiddenByCheckCompoundPattern(AWord, AInitialWordJoint, AFirstPartWordBaseItem, AWordBaseItem) then
|
|
AWordBaseItem := nil;
|
|
|
|
if (AWordBaseItem <> nil) and
|
|
(((ATakenPrefix <> nil) and
|
|
ATakenPrefix.IsCompatibleWithFlag(FCompoundForbidFlag)) or
|
|
((ATakenSuffix <> nil) and
|
|
ATakenSuffix.IsCompatibleWithFlag(FCompoundForbidFlag))) then
|
|
AWordBaseItem := nil;
|
|
|
|
if IsForbiddenOrNoSuggestWord(AWordBaseItem, ASuggest) then
|
|
begin
|
|
Result := nil;
|
|
Exit;
|
|
end;
|
|
|
|
if IsHungarian then
|
|
begin
|
|
Inc(ASyllableCount, GetSyllableCount(AWord + AInitialWordJoint, StrLen(AWord + AInitialWordJoint)));
|
|
|
|
if FSavedSuffixInfo.AppendString <> nil then
|
|
Dec(ASyllableCount, GetSyllableCount(FSavedSuffixInfo.AppendString, StrLen(FSavedSuffixInfo.AppendString)));
|
|
|
|
if (ATakenPrefix <> nil) and (GetSyllableCount(ATakenPrefix.AppendString, StrLen(ATakenPrefix.AppendString)) > 1) then
|
|
Inc(AWordPartIndex);
|
|
|
|
if FSyllableNum <> nil then
|
|
case Chr(FSavedSuffixInfo.Flag) of
|
|
'c': Inc(ASyllableCount, 2);
|
|
'J': Inc(ASyllableCount, 1);
|
|
'I': if AWordBaseItem.IsCompatibleWithFlag(Ord('J')) then Inc(ASyllableCount, 1);
|
|
end;
|
|
end;
|
|
|
|
CompoundRootCheck(AWordBaseItem, AWordPartIndex);
|
|
|
|
if (AWordBaseItem <> nil) and
|
|
(((FCompoundWordMax = -1) or (AWordPartIndex + 1 < FCompoundWordMax)) or
|
|
((FMaxCompoundSyllable <> 0) and (ASyllableCount <= FMaxCompoundSyllable))) and
|
|
(not FCheckCompoundDup or (AWordBaseItem <> AFirstPartWordBaseItem)) then
|
|
begin
|
|
Result := AFirstPartWordBaseItem;
|
|
Exit;
|
|
end;
|
|
|
|
ASyllableCount := ASyllableCountStore2;
|
|
AWordPartIndex := AWordPartIndexStore2;
|
|
|
|
if AWordPartIndex < AWordPartMaxCount then
|
|
begin
|
|
AWordBaseItem := CompoundCheck(AInitialWordForm + AInitialWordJoint, AWordPartIndex + 1,
|
|
ASyllableCount, AWordPartMaxCount, wnum + 1, words, False, ASuggest);
|
|
if (AWordBaseItem <> nil) and (
|
|
not ((ATableIndex = 0) xor IsForbiddenByCheckCompoundPattern(AWord,
|
|
AInitialWordJoint, AFirstPartWordBaseItem, AWordBaseItem))) then
|
|
AWordBaseItem := nil;
|
|
end
|
|
else
|
|
AWordBaseItem := nil;
|
|
if AWordBaseItem <> nil then
|
|
begin
|
|
Result := AFirstPartWordBaseItem;
|
|
Exit;
|
|
end;
|
|
until not ADoubleCharacter or ACheckWordWithoutTripleRemoving;
|
|
|
|
if ACheckWordWithoutTripleRemoving then
|
|
begin
|
|
Inc(ACompoundWordJoint);
|
|
ACheckWordWithoutTripleRemoving := False;
|
|
ADoubleCharacter := False;
|
|
end;
|
|
end;
|
|
Inc(ATableIndex);
|
|
until not (FCheckCompoundPatternTable.IsSimplified and (ATableIndex <= FCheckCompoundPatternTable.Count));
|
|
|
|
ATableIndex := 0;
|
|
AWordPartIndex := AWordPartIndexStore;
|
|
ASyllableCount := ASyllableCountStore;
|
|
|
|
Inc(ACompoundWordJoint);
|
|
end;
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.ProcessSuffixCheck(const AWord: PAnsiChar; AWordLength, AOptions: Integer;
|
|
APrefix: TdxPrefix; var ATakenSuffix: TdxSuffix; wlst: PPAnsiChar; maxSug: Integer; ns: PInteger;
|
|
const ACompatibleFlag, ACompoundPartFlag: Word; ACompoundWordPart: TdxCompoundWordPart): TdxHunspellWordItem;
|
|
var
|
|
ASuffix: TdxSuffix;
|
|
AIncompatibleFlag: Word;
|
|
begin
|
|
Result := nil;
|
|
|
|
AIncompatibleFlag := IfThen(ACompoundWordPart <> cwpNone, NullFlag, FOnlyInCompound);
|
|
|
|
ASuffix := TdxSuffix(FSuffixTableArrangedByAppendString[0]);
|
|
|
|
while (ASuffix <> nil) and (Result = nil) do
|
|
begin
|
|
if (ACompatibleFlag = 0) or (ASuffix.CompatibleFlags <> nil) then
|
|
begin
|
|
if ASuffix.CanUseInTheMiddleOfCompoundWords(ACompoundWordPart) and
|
|
AreAffixesBothCircumfixesOrNot(APrefix, ASuffix) and
|
|
ASuffix.CanUseInSimpleWordsOrIsFogemorpheme(ACompoundWordPart) and
|
|
((ACompatibleFlag <> NullFlag) or not ASuffix.IsCompatibleWithFlag(FNeedAffix) or
|
|
(APrefix <> nil) and not APrefix.IsCompatibleWithFlag(FNeedAffix)) then
|
|
begin
|
|
Result := ASuffix.CheckWord(AWord, AWordLength, AOptions, APrefix, wlst, maxSug, ns,
|
|
ACompatibleFlag, ACompoundPartFlag, AIncompatibleFlag);
|
|
if Result <> nil then
|
|
ATakenSuffix := ASuffix;
|
|
end;
|
|
end;
|
|
ASuffix := TdxSuffix(ASuffix.Next);
|
|
end;
|
|
|
|
if Result = nil then
|
|
begin
|
|
ASuffix := TdxSuffix(FSuffixTableArrangedByAppendString[Ord((AWord + AWordLength - 1)^)]);
|
|
|
|
while (ASuffix <> nil) and (Result = nil) do
|
|
begin
|
|
if IsTrailingReversedSubset(ASuffix.AppendString, AWord + AWordLength - 1, AWordLength) then
|
|
begin
|
|
if ASuffix.CanUseInTheMiddleOfCompoundWords(ACompoundWordPart) and
|
|
AreAffixesBothCircumfixesOrNot(APrefix, ASuffix) and
|
|
ASuffix.CanUseInSimpleWordsOrIsFogemorpheme(ACompoundWordPart) and
|
|
((ACompatibleFlag <> 0) or not ASuffix.IsCompatibleWithFlag(FNeedAffix) or
|
|
(APrefix <> nil) and not APrefix.IsCompatibleWithFlag(FNeedAffix)) then
|
|
begin
|
|
Result := ASuffix.CheckWord(AWord, AWordLength, AOptions, APrefix, wlst, maxSug, ns,
|
|
ACompatibleFlag, ACompoundPartFlag, AIncompatibleFlag);
|
|
if Result <> nil then
|
|
begin
|
|
ATakenSuffix := ASuffix;
|
|
FSavedSuffixInfo.Flag := ASuffix.Flag;
|
|
if ASuffix.CompatibleFlags = nil then
|
|
FSavedSuffixInfo.AppendString := ASuffix.AppendString;
|
|
end;
|
|
end;
|
|
ASuffix := TdxSuffix(ASuffix.NextSimilar);
|
|
end
|
|
else
|
|
ASuffix := TdxSuffix(ASuffix.NextDifferent);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.ProcessTwoSuffixCheck(const AWord: PAnsiChar; AWordLength, AOptions: Integer;
|
|
APrefix: TdxPrefix; var ATakenSuffix: TdxSuffix; const ACompoundPartFlag: Word): TdxHunspellWordItem;
|
|
var
|
|
ASuffix: TdxSuffix;
|
|
begin
|
|
Result := nil;
|
|
|
|
ASuffix := TdxSuffix(FSuffixTableArrangedByAppendString[0]);
|
|
while (ASuffix <> nil) and (Result = nil) do
|
|
begin
|
|
if FCompatibleFlags[ASuffix.Flag] then
|
|
Result := ASuffix.MakeInitialWordFormAndProcessSuffixCheck(AWord,
|
|
AWordLength, AOptions, APrefix, ATakenSuffix, ACompoundPartFlag);
|
|
ASuffix := TdxSuffix(ASuffix.Next);
|
|
end;
|
|
|
|
if Result = nil then
|
|
begin
|
|
ASuffix := TdxSuffix(FSuffixTableArrangedByAppendString[Ord((AWord + AWordLength - 1)^)]);
|
|
|
|
while (ASuffix <> nil) and (Result = nil) do
|
|
begin
|
|
if IsTrailingReversedSubset(ASuffix.AppendString, AWord + AWordLength - 1, AWordLength) then
|
|
begin
|
|
if FCompatibleFlags[ASuffix.Flag] then
|
|
begin
|
|
Result := ASuffix.MakeInitialWordFormAndProcessSuffixCheck(AWord,
|
|
AWordLength, AOptions, APrefix, ATakenSuffix, ACompoundPartFlag);
|
|
if Result <> nil then
|
|
begin
|
|
FSavedSuffixInfo.Flag := ASuffix.Flag;
|
|
if ASuffix.CompatibleFlags = nil then
|
|
FSavedSuffixInfo.AppendString := ASuffix.AppendString;
|
|
end;
|
|
end;
|
|
ASuffix := TdxSuffix(ASuffix.NextSimilar);
|
|
end
|
|
else
|
|
ASuffix := TdxSuffix(ASuffix.NextDifferent);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.AffixCheck(const AWord: PAnsiChar; AWordLength: Integer;
|
|
var ATakenPrefix: TdxPrefix; var ATakenSuffix: TdxSuffix; const ACompoundPartFlag: Word;
|
|
ACompoundWordPart: TdxCompoundWordPart): TdxHunspellWordItem;
|
|
begin
|
|
Result := ProcessPrefixCheck(AWord, AWordLength, ATakenPrefix, ATakenSuffix,
|
|
ACompoundWordPart, ACompoundPartFlag);
|
|
if Result = nil then
|
|
begin
|
|
Result := ProcessSuffixCheck(AWord, AWordLength, 0, nil, ATakenSuffix, nil,
|
|
0, nil, NullFlag, ACompoundPartFlag, ACompoundWordPart);
|
|
if FCompatibleFlagsExist then
|
|
begin
|
|
ATakenSuffix := nil;
|
|
ATakenPrefix := nil;
|
|
if Result = nil then
|
|
begin
|
|
Result := ProcessTwoSuffixCheck(AWord, AWordLength, 0, nil, ATakenSuffix, ACompoundPartFlag);
|
|
if Result = nil then
|
|
Result := ProcessPrefixWithSuffixesCheck(AWord, AWordLength,
|
|
ATakenPrefix, ATakenSuffix, cwpNone, ACompoundPartFlag);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.EncodeFlag(AFlag: Word): PAnsiChar;
|
|
begin
|
|
Result := FWordBaseManager.EncodeFlag(AFlag);
|
|
end;
|
|
|
|
procedure TdxHunspellAffixManager.SetCompatibleFlags(AIndex: Integer; AValue: Boolean);
|
|
begin
|
|
FCompatibleFlags[AIndex] := AValue;
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.Lookup(const AWord: PAnsiChar): TdxHunspellWordItem;
|
|
begin
|
|
Result := FWordBaseManager.Lookup(AWord);
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.ParseCompoundSyllable(ALine: PAnsiChar;
|
|
AAffixFileManager: TdxHunspellReader): Boolean;
|
|
var
|
|
ALineCursor, APiece: PAnsiChar;
|
|
I, APartCount: Integer;
|
|
begin
|
|
Result := False;
|
|
ALineCursor := ALine;
|
|
APiece := StrSeparate(@ALineCursor, #0);
|
|
APartCount := 0;
|
|
I := 0;
|
|
while APiece <> nil do
|
|
begin
|
|
if APiece^ <> #0 then
|
|
begin
|
|
case I of
|
|
0: Inc(APartCount);
|
|
1: begin
|
|
FMaxCompoundSyllable := StrInt(APiece);
|
|
Inc(APartCount);
|
|
end;
|
|
2: begin
|
|
if not IsUTF8 then
|
|
FCompoundVowels := StrNew(APiece)
|
|
else
|
|
begin
|
|
//TODO:
|
|
end;
|
|
Inc(APartCount);
|
|
end;
|
|
end;
|
|
Inc(I);
|
|
end;
|
|
APiece := StrSeparate(@ALineCursor, #0);
|
|
end;
|
|
if APartCount < 2 then
|
|
begin
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
if APartCount = 2 then
|
|
FCompoundVowels := StrNew(PAnsiChar('aeiouAEIOU'));
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.ParseRep(ALine: PAnsiChar; AAffixFileManager: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := not FReplaceTable.ReadData(ALine, AAffixFileManager);
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.AreAffixesBothCircumfixesOrNot(APrefix, ASuffix: TdxAffix): Boolean;
|
|
begin
|
|
Result := (FCircumfix = NullFlag) or
|
|
not (((APrefix <> nil) and APrefix.IsCircumfix) xor ASuffix.IsCircumfix);
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.CanBeFirstPartInCompoundWord(
|
|
AWordBaseItem: TdxHunspellWordItem; AWordPartIndex: Cardinal): Boolean;
|
|
begin
|
|
Result := ((FCompoundFlag <> 0) and
|
|
AWordBaseItem.IsCompatibleWithFlag(FCompoundFlag)) or
|
|
((AWordPartIndex = 0) and (FCompoundBegin <> 0) and
|
|
AWordBaseItem.IsCompatibleWithFlag(FCompoundBegin)) or
|
|
((AWordPartIndex > 0) and (FCompoundMiddle <> 0) and
|
|
AWordBaseItem.IsCompatibleWithFlag(FCompoundMiddle));
|
|
end;
|
|
|
|
procedure TdxHunspellAffixManager.CompoundRootCheck(
|
|
AWordBaseItem: TdxHunspellWordItem; var AWordPartIndex: SmallInt);
|
|
begin
|
|
if (AWordBaseItem <> nil) and (FCompoundRoot <> 0) and
|
|
AWordBaseItem.IsCompatibleWithFlag(FCompoundRoot) then
|
|
Inc(AWordPartIndex);
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.IsForbiddenOrNoSuggestWord(
|
|
AWordBaseItem: TdxHunspellWordItem; ASuggest: Boolean): Boolean;
|
|
begin
|
|
Result := (AWordBaseItem <> nil) and
|
|
(AWordBaseItem.IsCompatibleWithFlag(FForbiddenWord) or
|
|
(ASuggest and (FNoSuggest <> 0) and AWordBaseItem.IsCompatibleWithFlag(FNoSuggest)));
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.IsWordPartSuitsCheckCompoundPatternTable(
|
|
AWordBaseItem: TdxHunspellWordItem; ATableIndex: Integer; AIsFirstWordPart: Boolean): Boolean;
|
|
var
|
|
AFlag: Word;
|
|
begin
|
|
Result := ATableIndex = 0;
|
|
if not Result then
|
|
begin
|
|
if AIsFirstWordPart then
|
|
AFlag := FCheckCompoundPatternTable[ATableIndex - 1].Condition
|
|
else
|
|
AFlag := FCheckCompoundPatternTable[ATableIndex - 1].Condition2;
|
|
Result := (AFlag = NullFlag) or AWordBaseItem.IsCompatibleWithFlag(AFlag);
|
|
end;
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.IsWordPartSuitsCompoundFlags(AWordBaseItem: TdxHunspellWordItem;
|
|
AWordPartIndex: SmallInt; AIsFirstWordPart: Boolean; words: PdxHunspellWordBaseTable): Boolean;
|
|
begin
|
|
Result := (words = nil) and AWordBaseItem.IsCompatibleWithFlag(FCompoundFlag);
|
|
if not Result then
|
|
begin
|
|
if AIsFirstWordPart then
|
|
Result := ((AWordPartIndex = 0) and
|
|
AWordBaseItem.IsCompatibleWithFlag(FCompoundBegin)) or
|
|
((AWordPartIndex <> 0) and (words = nil) and
|
|
AWordBaseItem.IsCompatibleWithFlag(FCompoundMiddle))
|
|
else
|
|
Result := (words = nil) and AWordBaseItem.IsCompatibleWithFlag(FCompoundEnd);
|
|
end;
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.IsTripleLettersExistAndForbid(AWord: PAnsiChar; AJoint: Cardinal): Boolean;
|
|
begin
|
|
Result := FCheckCompoundTriple and
|
|
(AWord[AJoint - 1] = AWord[AJoint]) and (
|
|
((AJoint > 1) and (AWord[AJoint - 1] = AWord[AJoint - 2])) or
|
|
((AJoint + 1 < StrLen(AWord)) and (AWord[AJoint - 1] = AWord[AJoint + 1])));
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.UseWithAffixOnly(AWordBaseItem: TdxHunspellWordItem): Boolean;
|
|
begin
|
|
Result := (FNeedAffix <> 0) and AWordBaseItem.IsCompatibleWithFlag(FNeedAffix);
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.HungarianCheck(AWordBaseItem: TdxHunspellWordItem;
|
|
hu_mov_rule: Boolean): Boolean;
|
|
begin
|
|
Result := IsHungarian and hu_mov_rule and (
|
|
AWordBaseItem.IsCompatibleWithFlag(Ord('F')) or
|
|
AWordBaseItem.IsCompatibleWithFlag(Ord('G')) or
|
|
AWordBaseItem.IsCompatibleWithFlag(Ord('H')));
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.HungarianCheck2(var AWordBaseItem: TdxHunspellWordItem;
|
|
AInitialWordForm: TWordFormArray; ACompoundWordJoint: Integer;
|
|
hu_mov_rule: Boolean; var ATakenPrefix: TdxPrefix; var ATakenSuffix: TdxSuffix): Boolean;
|
|
|
|
function DoAffixCheck: Boolean;
|
|
begin
|
|
AWordBaseItem := AffixCheck(AInitialWordForm, ACompoundWordJoint, ATakenPrefix, ATakenSuffix);
|
|
Result := AWordBaseItem <> nil;
|
|
end;
|
|
|
|
begin
|
|
Result := (AWordBaseItem = nil) and IsHungarian and hu_mov_rule and DoAffixCheck and
|
|
((ATakenSuffix <> nil) and (ATakenSuffix.IsCompatibleWithFlag(Ord('x')) or ATakenSuffix.IsCompatibleWithFlag(Ord('%'))));
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.ParseAffix(ALine: PAnsiChar; const IsPrefix: Boolean;
|
|
AAffixFileManager: TdxHunspellReader; AExistentAffixFlags: TdxExistentAffixFlags): Boolean;
|
|
var
|
|
AAffixItem: TdxAffixItemTable;
|
|
begin
|
|
if IsPrefix then
|
|
AAffixItem := TdxPrefixItemTable.Create(FWordBaseManager, Self, AExistentAffixFlags)
|
|
else
|
|
AAffixItem := TdxSuffixItemTable.Create(FWordBaseManager, Self, AExistentAffixFlags);
|
|
try
|
|
Result := not AAffixItem.ReadData(ALine, AAffixFileManager);
|
|
if not Result then
|
|
AAffixItem.BuildAffixes
|
|
else
|
|
dxHunspellError(AAffixItem.Flag + ' affix is invalid in file ' + FAffixFilePath);
|
|
finally
|
|
AAffixItem.Free;
|
|
end;
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.GetIsCompoundWordsAvailable: Boolean;
|
|
begin
|
|
Result := (FCompoundFlag <> NullFlag) or (FCompoundBegin <> NullFlag) or
|
|
(FCompoundRuleTable.Count > 0);
|
|
end;
|
|
|
|
function TdxHunspellAffixManager.GetParseClasses: TObjectList;
|
|
begin
|
|
Result := TObjectList.Create;
|
|
Result.Add(TTryReader.Create(Self));
|
|
Result.Add(TSetReader.Create(Self));
|
|
Result.Add(TComplexPrefixesReader.Create(Self));
|
|
Result.Add(TCompoundFlagReader.Create(Self));
|
|
Result.Add(TCompoundBeginReader.Create(Self));
|
|
Result.Add(TCompoundEndReader.Create(Self));
|
|
Result.Add(TCompoundMiddleReader.Create(Self));
|
|
Result.Add(TCompoundWordMaxReader.Create(Self));
|
|
Result.Add(TCompoundRootReader.Create(Self));
|
|
Result.Add(TCompoundPermitFlagReader.Create(Self));
|
|
Result.Add(TCompoundForbidFlagReader.Create(Self));
|
|
Result.Add(TCheckCompoundDupReader.Create(Self));
|
|
Result.Add(TCheckCompoundRepReader.Create(Self));
|
|
Result.Add(TCheckCompoundTripleReader.Create(Self));
|
|
Result.Add(TSimplifiedTripleReader.Create(Self));
|
|
Result.Add(TCheckCompoundCaseReader.Create(Self));
|
|
Result.Add(TNoSuggestReader.Create(Self));
|
|
Result.Add(TForbiddenWordReader.Create(Self));
|
|
Result.Add(TLemmaPresentReader.Create(Self));
|
|
Result.Add(TCircumfixReader.Create(Self));
|
|
Result.Add(TOnlyInCompoundReader.Create(Self));
|
|
Result.Add(TPseudoRootReader.Create(Self));
|
|
Result.Add(TNeedAffixReader.Create(Self));
|
|
Result.Add(TCompoundMinReader.Create(Self));
|
|
Result.Add(TCompoundSyllableReader.Create(Self));
|
|
Result.Add(TSyllableNumReader.Create(Self));
|
|
Result.Add(TWordCharsReader.Create(Self));
|
|
Result.Add(TIgnoreReader.Create(Self));
|
|
Result.Add(TRepReader.Create(Self));
|
|
Result.Add(TIConvReader.Create(Self));
|
|
Result.Add(TOConvReader.Create(Self));
|
|
Result.Add(TCheckCompoundPatternReader.Create(Self));
|
|
Result.Add(TCompoundRuleReader.Create(Self));
|
|
Result.Add(TMapReader.Create(Self));
|
|
Result.Add(TBreakReader.Create(Self));
|
|
Result.Add(TLangReader.Create(Self));
|
|
Result.Add(TVersionReader.Create(Self));
|
|
Result.Add(TNoSplitSugsReader.Create(Self));
|
|
Result.Add(TFullStripReader.Create(Self));
|
|
Result.Add(TSugsWithDotsReader.Create(Self));
|
|
Result.Add(TKeepCaseReader.Create(Self));
|
|
Result.Add(TSubStandardReader.Create(Self));
|
|
Result.Add(TCheckSharpsReader.Create(Self));
|
|
Result.Add(TPrefixReader.Create(Self));
|
|
Result.Add(TSuffixReader.Create(Self));
|
|
end;
|
|
|
|
procedure TdxHunspellAffixManager.SetLanguage(Value: Integer);
|
|
begin
|
|
FLanguage := Value;
|
|
FIsHungarian := Language = LanguageHu; //TODO:
|
|
end;
|
|
|
|
{ TdxAffix }
|
|
|
|
constructor TdxAffix.Create(AAffixManager: TdxHunspellAffixManager;
|
|
AAffixItem: PdxAffixItem; AFlag: Word; AOptions: ShortInt);
|
|
begin
|
|
FAffixManager := AAffixManager;
|
|
|
|
FFlag := AFlag;
|
|
FStripString := AAffixItem.FStripString;
|
|
FAppendString := AAffixItem.FAppendString;
|
|
FStripStringLength := AAffixItem.FStripStringLength;
|
|
FAppendStringLength := AAffixItem.FAppendStringLength;
|
|
FConditionLength := AAffixItem.FConditionLength;
|
|
FOptions := AOptions;
|
|
|
|
FConditions := AllocMem(SizeOf(TdxAffixCondition));
|
|
if FOptions and aeLONGCOND <> 0 then
|
|
begin
|
|
Move(AAffixItem.ConditionFirstPart, FConditions.Condition, MaxConditionLength);
|
|
FConditions.ConditionSecondPart := AAffixItem.ConditionSecondPart;
|
|
end
|
|
else
|
|
Move(AAffixItem.Condition, FConditions.Condition, MaxConditionLength);
|
|
|
|
FMorphologicalDescription := AAffixItem.FMorphologicalDescription;
|
|
FCompatibleFlags := AAffixItem.FCompatibleFlags;
|
|
end;
|
|
|
|
destructor TdxAffix.Destroy;
|
|
begin
|
|
FFlag := 0;
|
|
StrDispose(FAppendString);
|
|
StrDispose(FStripString);
|
|
FAppendString := nil;
|
|
FStripString := nil;
|
|
if FOptions and aeLONGCOND <> 0 then
|
|
StrDispose(FConditions.ConditionSecondPart);
|
|
FreeMem(FConditions, SizeOf(TdxAffixCondition));
|
|
if (FMorphologicalDescription <> nil) and (FOptions and aoAffixMorphologyTable = 0) then
|
|
StrDispose(FMorphologicalDescription);
|
|
FreeAndNil(FCompatibleFlags);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TdxAffix.CanUseInSimpleWordsOrIsFogemorpheme(ACompoundWordPart: TdxCompoundWordPart): Boolean;
|
|
begin
|
|
Result := (ACompoundWordPart <> cwpNone) or
|
|
not IsCompatibleWithFlag(AffixManager.OnlyInCompound);
|
|
end;
|
|
|
|
function TdxAffix.CanUseInTheMiddleOfCompoundWords(ACompoundWordPart: TdxCompoundWordPart): Boolean;
|
|
begin
|
|
Result := CanUseInCompoundWordPart(ACompoundWordPart) or
|
|
IsCompatibleWithFlag(AffixManager.FCompoundPermitFlag);
|
|
end;
|
|
|
|
function TdxAffix.GetNextConditionChar(AConditionCursor: PAnsiChar): PAnsiChar;
|
|
begin
|
|
Result := nil;
|
|
if AConditionCursor <> nil then
|
|
begin
|
|
Inc(AConditionCursor);
|
|
if FOptions and aeLONGCOND <> 0 then
|
|
begin
|
|
if AConditionCursor = FConditions.Condition + MaxConditionLength then
|
|
AConditionCursor := FConditions.ConditionSecondPart;
|
|
end
|
|
else
|
|
if AConditionCursor = FConditions.Condition + MaxConditionLength then
|
|
Exit;
|
|
if AConditionCursor^ <> #0 then
|
|
Result := AConditionCursor;
|
|
end;
|
|
end;
|
|
|
|
function TdxAffix.IsCompatibleWithFlag(AFlag: Word; CompatibleIfNull: Boolean = False): Boolean;
|
|
begin
|
|
Result := (CompatibleFlags <> nil) and
|
|
CompatibleFlags.ContainsFlag(AFlag);
|
|
if CompatibleIfNull then
|
|
Result := Result or (AFlag = NullFlag);
|
|
end;
|
|
|
|
function TdxAffix.IsPrefixSuffixUnion(AOptions: ShortInt): Boolean;
|
|
begin
|
|
Result := AOptions and aoPrefixSuffixUnion <> 0
|
|
end;
|
|
|
|
function TdxAffix.IsWithoutAffixWordLengthCorrect(ALengthWithoutAffix: Integer): Boolean;
|
|
begin
|
|
Result := ((ALengthWithoutAffix > 0) or
|
|
(ALengthWithoutAffix = 0) and AffixManager.FullStrip) and
|
|
(ALengthWithoutAffix + FStripStringLength >= FConditionLength);
|
|
end;
|
|
|
|
procedure TdxAffix.SearchConditionGroupEnd(var AConditionCursor: PAnsiChar);
|
|
var
|
|
ANextConditionChar: PAnsiChar;
|
|
begin
|
|
ANextConditionChar := GetNextConditionChar(AConditionCursor);
|
|
while (AConditionCursor <> nil) and (AConditionCursor^ <> ']') and
|
|
(ANextConditionChar <> nil) do
|
|
begin
|
|
AConditionCursor := ANextConditionChar;
|
|
ANextConditionChar := GetNextConditionChar(AConditionCursor);
|
|
end;
|
|
end;
|
|
|
|
function TdxAffix.IsCircumfix: Boolean;
|
|
begin
|
|
Result := IsCompatibleWithFlag(AffixManager.FCircumfix);
|
|
end;
|
|
|
|
function TdxAffix.GetAppendString: PAnsiChar;
|
|
begin
|
|
Result := FAppendString;
|
|
end;
|
|
|
|
function TdxAffix.GetPrefixSuffixUnion: Boolean;
|
|
begin
|
|
Result := IsPrefixSuffixUnion(FOptions);
|
|
end;
|
|
|
|
{ TdxPrefix }
|
|
|
|
function TdxPrefix.CanUseInCompoundWordPart(ACompoundWordPart: TdxCompoundWordPart): Boolean;
|
|
begin
|
|
Result := ACompoundWordPart <> cwpLast;
|
|
end;
|
|
|
|
function TdxPrefix.CheckWord(const AWord: PAnsiChar; AWordLength: Integer; var ATakenSuffix: TdxSuffix;
|
|
ACompoundWordPart: TdxCompoundWordPart; const ACompoundPartFlag: Word = NullFlag): TdxHunspellWordItem;
|
|
var
|
|
AInitialWordFormLength: Integer;
|
|
AWordBaseTableItem: TdxHunspellWordItem;
|
|
AInitialWordForm: array[0..MAXWORDUTF8LEN + 3] of AnsiChar;
|
|
begin
|
|
Result := nil;
|
|
AInitialWordFormLength := AWordLength - AppendStringLength;
|
|
|
|
if IsWithoutAffixWordLengthCorrect(AInitialWordFormLength) then
|
|
begin
|
|
if FStripStringLength <> 0 then
|
|
StrCopy(AInitialWordForm, FStripString);
|
|
StrCopy(AInitialWordForm + FStripStringLength, AWord + AppendStringLength);
|
|
|
|
if IsWordSuitableToCondition(AInitialWordForm) then
|
|
begin
|
|
Inc(AInitialWordFormLength, FStripStringLength);
|
|
AWordBaseTableItem := AffixManager.Lookup(AInitialWordForm);
|
|
if AWordBaseTableItem <> nil then
|
|
repeat
|
|
if AWordBaseTableItem.IsCompatibleWithFlag(FFlag) and
|
|
not IsCompatibleWithFlag(AffixManager.FNeedAffix) and
|
|
(AWordBaseTableItem.IsCompatibleWithFlag(ACompoundPartFlag, True) or
|
|
IsCompatibleWithFlag(ACompoundPartFlag)) then
|
|
Result := AWordBaseTableItem;
|
|
AWordBaseTableItem := AWordBaseTableItem.NextHomonym;
|
|
until (AWordBaseTableItem = nil) or (Result <> nil);
|
|
|
|
if Result = nil then
|
|
begin
|
|
if PrefixSuffixUnion then
|
|
Result := AffixManager.ProcessSuffixCheck(AInitialWordForm,
|
|
AInitialWordFormLength, aoPrefixSuffixUnion, Self, ATakenSuffix, nil,
|
|
0, nil, NullFlag, ACompoundPartFlag, ACompoundWordPart);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxPrefix.MakeInitialWordFormAndProcessTwoSuffixCheck(const AWord: PAnsiChar;
|
|
AWordLength: Integer; var ATakenSuffix: TdxSuffix;
|
|
ACompoundWordPart: TdxCompoundWordPart;
|
|
const ACompoundPartFlag: Word = NullFlag): TdxHunspellWordItem;
|
|
var
|
|
AInitialWordFormLength: Integer;
|
|
AInitialWordForm: array[0..MAXWORDUTF8LEN + 3] of AnsiChar;
|
|
begin
|
|
Result := nil;
|
|
AInitialWordFormLength := AWordLength - AppendStringLength;
|
|
if IsWithoutAffixWordLengthCorrect(AInitialWordFormLength) then
|
|
begin
|
|
if FStripStringLength <> 0 then
|
|
StrCopy(AInitialWordForm, FStripString);
|
|
StrCopy(AInitialWordForm + FStripStringLength, AWord + AppendStringLength);
|
|
if IsWordSuitableToCondition(AInitialWordForm) then
|
|
begin
|
|
Inc(AInitialWordFormLength, FStripStringLength);
|
|
if PrefixSuffixUnion and (ACompoundWordPart <> cwpFirst) then
|
|
Result := AffixManager.ProcessTwoSuffixCheck(AInitialWordForm,
|
|
AInitialWordFormLength, aoPrefixSuffixUnion, Self, ATakenSuffix,
|
|
ACompoundPartFlag);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxPrefix.IsWordSuitableToCondition(AWord: PAnsiChar): Boolean;
|
|
|
|
procedure GoForward;
|
|
begin
|
|
Inc(AWord);
|
|
while (FOptions and aeUTF8 <> 0) and (Ord(AWord^) and $C0 = $80) do
|
|
Inc(AWord);
|
|
end;
|
|
|
|
var
|
|
AWordCursor: PAnsiChar;
|
|
ANegative: Boolean;
|
|
AIsGroup: Boolean;
|
|
AConditionCursor: PAnsiChar;
|
|
|
|
begin
|
|
Result := False;
|
|
AWordCursor := nil;
|
|
ANegative := False;
|
|
AIsGroup := False;
|
|
if FConditionLength = 0 then
|
|
begin
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
AConditionCursor := FConditions.Condition;
|
|
while True do
|
|
begin
|
|
case AConditionCursor^ of
|
|
#0:
|
|
begin
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
'[':
|
|
begin
|
|
ANegative := False;
|
|
AIsGroup := False;
|
|
AConditionCursor := GetNextConditionChar(AConditionCursor);
|
|
AWordCursor := AWord;
|
|
end;
|
|
'^':
|
|
begin
|
|
AConditionCursor := GetNextConditionChar(AConditionCursor);
|
|
ANegative := True;
|
|
end;
|
|
']':
|
|
begin
|
|
if ANegative and AIsGroup or not ANegative and not AIsGroup then
|
|
Exit;
|
|
AWordCursor := nil;
|
|
AConditionCursor := GetNextConditionChar(AConditionCursor);
|
|
if not AIsGroup then
|
|
GoForward;
|
|
if (AWord^ = #0) and (AConditionCursor <> nil) then
|
|
Exit;
|
|
end;
|
|
'.':
|
|
if AWordCursor = nil then
|
|
begin
|
|
AConditionCursor := GetNextConditionChar(AConditionCursor);
|
|
GoForward;
|
|
if (AWord^ = #0) and (AConditionCursor <> nil) then
|
|
Exit;
|
|
end;
|
|
else
|
|
if AWord^ = AConditionCursor^ then
|
|
begin
|
|
Inc(AWord);
|
|
AConditionCursor := GetNextConditionChar(AConditionCursor);
|
|
if (FOptions and aeUTF8 <> 0) and (Ord((AWord - 1)^) and $80 <> 0) then
|
|
begin
|
|
while (AConditionCursor <> nil) and (Ord(AConditionCursor^) and $C0 = $80) do
|
|
begin
|
|
if (AConditionCursor^ <> AWord^) then
|
|
begin
|
|
if AWordCursor = nil then
|
|
Exit;
|
|
AWord := AWordCursor;
|
|
Break;
|
|
end;
|
|
AConditionCursor := GetNextConditionChar(AConditionCursor);
|
|
Inc(AWord);
|
|
end;
|
|
if (AWordCursor <> nil) and (AWord <> AWordCursor) then
|
|
begin
|
|
AIsGroup := True;
|
|
SearchConditionGroupEnd(AConditionCursor);
|
|
end;
|
|
end
|
|
else
|
|
if AWordCursor <> nil then
|
|
begin
|
|
AIsGroup := True;
|
|
SearchConditionGroupEnd(AConditionCursor);
|
|
end;
|
|
end
|
|
else
|
|
if AWordCursor <> nil then
|
|
AConditionCursor := GetNextConditionChar(AConditionCursor)
|
|
else
|
|
Exit;
|
|
end;
|
|
if AConditionCursor = nil then
|
|
begin
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ TdxSuffix }
|
|
|
|
constructor TdxSuffix.Create(AAffixManager: TdxHunspellAffixManager;
|
|
AAffixItem: PdxAffixItem; AFlag: Word; AOptions: ShortInt);
|
|
begin
|
|
inherited Create(AAffixManager, AAffixItem, AFlag, AOptions);
|
|
FReverseAppendString := StrCopyReverse(FAppendString);
|
|
end;
|
|
|
|
destructor TdxSuffix.Destroy;
|
|
begin
|
|
StrDispose(FReverseAppendString);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TdxSuffix.CanUseInCompoundWordPart(ACompoundWordPart: TdxCompoundWordPart): Boolean;
|
|
begin
|
|
Result := ACompoundWordPart <> cwpFirst;
|
|
end;
|
|
|
|
function TdxSuffix.GetWordWithAffix(const AWord: PAnsiChar; AWordLength: Integer): PAnsiChar;
|
|
var
|
|
ATempWord: array[0..MAXWORDUTF8LEN + 3] of AnsiChar;
|
|
begin
|
|
Result := nil;
|
|
if ((AWordLength > FStripStringLength) or (AWordLength = 0) and (AffixManager.FullStrip)) and
|
|
(AWordLength >= FConditionLength) and IsWordSuitableToCondition(AWord + AWordLength, AWord) and
|
|
((FStripStringLength = 0) or (StrComp(AWord + AWordLength - FStripStringLength, FStripString) = 0)) and
|
|
(MAXWORDUTF8LEN + 4 > AWordLength + AppendStringLength - FStripStringLength) then
|
|
begin
|
|
StrCopy(ATempWord, AWord);
|
|
if AppendStringLength <> 0 then
|
|
StrCopy(ATempWord + AWordLength - FStripStringLength, FAppendString)
|
|
else
|
|
(ATempWord + AWordLength - FStripStringLength)^ := #0;
|
|
Result := StrNew(ATempWord);
|
|
end;
|
|
end;
|
|
|
|
function TdxSuffix.CheckWord(const AWord: PAnsiChar; AWordLength, AOptions: Integer;
|
|
APrefix: TdxPrefix; wlst: PPAnsiChar; maxSug: Integer; ns: PInteger;
|
|
const ACompatibleFlag: Word = NullFlag; const ACompoundPartFlag: Word = NullFlag;
|
|
const AIncompatibleFlag: Word = NullFlag): TdxHunspellWordItem;
|
|
|
|
function IsIncompatibleWithFlag(AWordBaseTableItem: TdxHunspellWordItem; AFlag: Word): Boolean;
|
|
begin
|
|
Result := (AFlag = 0) or not AWordBaseTableItem.IsCompatibleWithFlag(AFlag);
|
|
end;
|
|
|
|
var
|
|
AInitialWordFormLength: Integer;
|
|
AWordBaseTableItem: TdxHunspellWordItem;
|
|
AInitialWordFormEndPointer: PAnsiChar;
|
|
AInitialWordForm: array[0..MAXWORDUTF8LEN + 3] of AnsiChar;
|
|
cwrd: Boolean;
|
|
K: Integer;
|
|
AElement: PPAnsiChar;
|
|
begin
|
|
Result := nil;
|
|
|
|
if IsPrefixSuffixUnion(AOptions) and not PrefixSuffixUnion then
|
|
Exit;
|
|
AInitialWordFormLength := AWordLength - AppendStringLength;
|
|
if IsWithoutAffixWordLengthCorrect(AInitialWordFormLength) then
|
|
begin
|
|
StrCopy(AInitialWordForm, AWord);
|
|
AInitialWordFormEndPointer := AInitialWordForm + AInitialWordFormLength;
|
|
if FStripStringLength <> 0 then
|
|
begin
|
|
StrCopy(AInitialWordFormEndPointer, FStripString);
|
|
Inc(AInitialWordFormLength, FStripStringLength);
|
|
AInitialWordFormEndPointer := AInitialWordForm + AInitialWordFormLength;
|
|
end
|
|
else
|
|
AInitialWordFormEndPointer^ := #0;
|
|
|
|
if IsWordSuitableToCondition(AInitialWordFormEndPointer, AInitialWordForm) then
|
|
begin
|
|
AWordBaseTableItem := AffixManager.Lookup(AInitialWordForm);
|
|
if AWordBaseTableItem <> nil then
|
|
begin
|
|
repeat
|
|
if (AWordBaseTableItem.IsCompatibleWithFlag(FFlag) or
|
|
(APrefix <> nil) and APrefix.IsCompatibleWithFlag(FFlag)) and
|
|
(not IsPrefixSuffixUnion(AOptions) or
|
|
AWordBaseTableItem.IsCompatibleWithFlag(APrefix.Flag) or
|
|
IsCompatibleWithFlag(APrefix.Flag)) and
|
|
IsCompatibleWithFlag(ACompatibleFlag, True) and
|
|
IsIncompatibleWithFlag(AWordBaseTableItem, AIncompatibleFlag) and
|
|
((ACompoundPartFlag = 0) or
|
|
(AWordBaseTableItem.IsCompatibleWithFlag(ACompoundPartFlag, True) or
|
|
IsCompatibleWithFlag(ACompoundPartFlag))) then
|
|
Result := AWordBaseTableItem;
|
|
AWordBaseTableItem := AWordBaseTableItem.NextHomonym;
|
|
until (AWordBaseTableItem = nil) or (Result <> nil);
|
|
end
|
|
else
|
|
if (wlst <> nil) and (ns^ < maxSug) then
|
|
begin
|
|
cwrd := True;
|
|
for K := 0 to ns^ - 1 do
|
|
if StrComp(AInitialWordForm, GetElementPointer(wlst, K)^) = 0 then
|
|
cwrd := False;
|
|
if cwrd then
|
|
begin
|
|
AElement := GetElementPointer(wlst, ns^);
|
|
AElement^ := StrNew(AInitialWordForm);
|
|
if AElement^ = nil then
|
|
begin
|
|
for K := 0 to ns^ - 1 do
|
|
StrDispose(GetElementPointer(wlst, K)^);
|
|
ns^ := -1;
|
|
Exit;
|
|
end;
|
|
Inc(ns^);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxSuffix.MakeInitialWordFormAndProcessSuffixCheck(const AWord: PAnsiChar; AWordLength, AOptions: Integer;
|
|
APrefix: TdxPrefix; var ATakenSuffix: TdxSuffix; const ACompoundPartFlag: Word = 0): TdxHunspellWordItem;
|
|
var
|
|
AInitialWordFormLength: Integer;
|
|
AInitialWordFormEndPointer: PAnsiChar;
|
|
AInitialWordForm: array[0..MAXWORDUTF8LEN + 3] of AnsiChar;
|
|
begin
|
|
Result := nil;
|
|
if IsPrefixSuffixUnion(AOptions) and not PrefixSuffixUnion then
|
|
Exit;
|
|
AInitialWordFormLength := AWordLength - AppendStringLength;
|
|
if IsWithoutAffixWordLengthCorrect(AInitialWordFormLength) then
|
|
begin
|
|
StrCopy(AInitialWordForm, AWord);
|
|
AInitialWordFormEndPointer := AInitialWordForm + AInitialWordFormLength;
|
|
if FStripStringLength <> 0 then
|
|
begin
|
|
StrCopy(AInitialWordFormEndPointer, FStripString);
|
|
Inc(AInitialWordFormLength, FStripStringLength);
|
|
AInitialWordFormEndPointer := AInitialWordForm + AInitialWordFormLength;
|
|
end
|
|
else
|
|
AInitialWordFormEndPointer^ := #0;
|
|
if IsWordSuitableToCondition(AInitialWordFormEndPointer, AInitialWordForm) then
|
|
begin
|
|
if APrefix <> nil then
|
|
begin
|
|
if IsCompatibleWithFlag(APrefix.Flag) then
|
|
Result := AffixManager.ProcessSuffixCheck(AInitialWordForm,
|
|
AInitialWordFormLength, 0, nil, ATakenSuffix, nil, 0, nil, FFlag,
|
|
ACompoundPartFlag)
|
|
else
|
|
Result := AffixManager.ProcessSuffixCheck(AInitialWordForm,
|
|
AInitialWordFormLength, AOptions, APrefix, ATakenSuffix, nil, 0, nil,
|
|
FFlag, ACompoundPartFlag);
|
|
end
|
|
else
|
|
Result := AffixManager.ProcessSuffixCheck(AInitialWordForm,
|
|
AInitialWordFormLength, 0, nil, ATakenSuffix, nil, 0, nil, FFlag,
|
|
ACompoundPartFlag);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxSuffix.GetAppendString: PAnsiChar;
|
|
begin
|
|
Result := FReverseAppendString;
|
|
end;
|
|
|
|
function TdxSuffix.getLM: TdxSuffix;
|
|
begin
|
|
Result := l_morph;
|
|
end;
|
|
|
|
function TdxSuffix.getRM: TdxSuffix;
|
|
begin
|
|
Result := r_morph;
|
|
end;
|
|
|
|
function TdxSuffix.getEQM: TdxSuffix;
|
|
begin
|
|
Result := eq_morph;
|
|
end;
|
|
|
|
function TdxSuffix.IsWordSuitableToCondition(AWordEnd, AWordBegin: PAnsiChar): Boolean;
|
|
|
|
procedure GoForward;
|
|
begin
|
|
while (FOptions and aeUTF8 <> 0) and (AWordEnd >= AWordBegin) and (Ord(AWordEnd^) and $C0 = $80) do
|
|
Dec(AWordEnd);
|
|
end;
|
|
|
|
var
|
|
AWordCursor: PAnsiChar;
|
|
ANegative: Boolean;
|
|
AIsGroup: Boolean;
|
|
AConditionCursor: PAnsiChar;
|
|
I: Integer;
|
|
|
|
begin
|
|
Result := False;
|
|
AWordCursor := nil;
|
|
ANegative := False;
|
|
AIsGroup := False;
|
|
if FConditionLength = 0 then
|
|
begin
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
AConditionCursor := FConditions.Condition;
|
|
Dec(AWordEnd);
|
|
I := 1;
|
|
while True do
|
|
begin
|
|
case AConditionCursor^ of
|
|
#0:
|
|
begin
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
'[':
|
|
begin
|
|
AConditionCursor := GetNextConditionChar(AConditionCursor);
|
|
AWordCursor := AWordEnd;
|
|
end;
|
|
'^':
|
|
begin
|
|
AConditionCursor := GetNextConditionChar(AConditionCursor);
|
|
ANegative := True;
|
|
end;
|
|
']':
|
|
begin
|
|
if not ANegative and not AIsGroup then
|
|
Exit;
|
|
Inc(I);
|
|
if not AIsGroup then
|
|
begin
|
|
GoForward;
|
|
Dec(AWordEnd);
|
|
end;
|
|
AWordCursor := nil;
|
|
ANegative := False;
|
|
AIsGroup := False;
|
|
AConditionCursor := GetNextConditionChar(AConditionCursor);
|
|
if (AWordEnd < AWordBegin) and (AConditionCursor <> nil) then
|
|
Exit;
|
|
end;
|
|
'.':
|
|
if AWordCursor = nil then
|
|
begin
|
|
AConditionCursor := GetNextConditionChar(AConditionCursor);
|
|
Dec(AWordEnd);
|
|
GoForward;
|
|
if AWordEnd < AWordBegin then
|
|
begin
|
|
if AConditionCursor = nil then
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
if (FOptions and aeUTF8 <> 0) and (Ord(AWordEnd^) and $80 <> 0) then
|
|
begin
|
|
Dec(AWordEnd);
|
|
if AWordEnd < AWordBegin then
|
|
begin
|
|
if AConditionCursor = nil then
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
else
|
|
if AWordEnd^ = AConditionCursor^ then
|
|
begin
|
|
AConditionCursor := GetNextConditionChar(AConditionCursor);
|
|
if (FOptions and aeUTF8 <> 0) and (Ord(AWordEnd^) and $80 <> 0) then
|
|
begin
|
|
Dec(AWordEnd);
|
|
while (AConditionCursor <> nil) and (AWordEnd >= AWordBegin) do
|
|
begin
|
|
if AConditionCursor^ <> AWordEnd^ then
|
|
begin
|
|
if AWordCursor = nil then
|
|
Exit;
|
|
AWordEnd := AWordCursor;
|
|
Break;
|
|
end;
|
|
if Ord(AConditionCursor^) and $C0 <> $80 then
|
|
Break;
|
|
AConditionCursor := GetNextConditionChar(AConditionCursor);
|
|
Dec(AWordEnd);
|
|
end;
|
|
if (AWordCursor <> nil) and (AWordEnd <> AWordCursor) then
|
|
begin
|
|
if ANegative then
|
|
Exit
|
|
else
|
|
if I = FConditionLength then
|
|
begin
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
AIsGroup := True;
|
|
SearchConditionGroupEnd(AConditionCursor);
|
|
Dec(AWordEnd);
|
|
end;
|
|
if (AConditionCursor <> nil) and (AConditionCursor^ <> ']') then
|
|
AConditionCursor := GetNextConditionChar(AConditionCursor);
|
|
end
|
|
else
|
|
if AWordCursor <> nil then
|
|
begin
|
|
if ANegative then
|
|
Exit
|
|
else
|
|
if I = FConditionLength then
|
|
begin
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
AIsGroup := True;
|
|
SearchConditionGroupEnd(AConditionCursor);
|
|
Dec(AWordEnd);
|
|
end;
|
|
if AWordCursor = nil then
|
|
begin
|
|
Inc(I);
|
|
Dec(AWordEnd);
|
|
end;
|
|
if (AWordEnd < AWordBegin) and (AConditionCursor <> nil) and
|
|
(AConditionCursor^ <> ']') then
|
|
Exit;
|
|
end
|
|
else
|
|
if AWordCursor <> nil then
|
|
AConditionCursor := GetNextConditionChar(AConditionCursor)
|
|
else
|
|
Exit;
|
|
end;
|
|
if AConditionCursor = nil then
|
|
begin
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ TdxAffixDataTable }
|
|
|
|
constructor TdxSpellCheckerDataTable.Create;
|
|
begin
|
|
// do nothing
|
|
end;
|
|
|
|
constructor TdxSpellCheckerDataTable.Create(ADataIdentifier: PAnsiChar);
|
|
begin
|
|
inherited Create;
|
|
FDataIdentifier := ADataIdentifier;
|
|
end;
|
|
|
|
destructor TdxSpellCheckerDataTable.Destroy;
|
|
begin
|
|
FreeData;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TdxSpellCheckerDataTable.AllocateData(ASize: Integer): Boolean;
|
|
begin
|
|
Result := True;
|
|
FreeData;
|
|
FSize := ASize;
|
|
try
|
|
FData := AllocMem(GetDataItemSize * ASize);
|
|
except
|
|
on EOutOfMemory do
|
|
begin
|
|
FSize := 0;
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
function TdxSpellCheckerDataTable.ReadData(ALine: PAnsiChar; AAffixFileManager: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := ReadDataHeader(ALine);
|
|
if Result then
|
|
Result := ParseData(AAffixFileManager);
|
|
if not Result then
|
|
FreeData;
|
|
end;
|
|
|
|
function TdxSpellCheckerDataTable.AddDataPiece(const APiece: PAnsiChar; ADataIndex,
|
|
APieceIndex: Integer): Boolean;
|
|
begin
|
|
Result := True;
|
|
if APieceIndex = 0 then
|
|
begin
|
|
Result := CheckDataType(APiece);
|
|
if Result then
|
|
begin
|
|
FCurrentDataIndex := ADataIndex;
|
|
InitializeItem(ADataIndex);
|
|
end;
|
|
end
|
|
else
|
|
if FCurrentDataIndex <> ADataIndex then
|
|
Result := False;
|
|
end;
|
|
|
|
function TdxSpellCheckerDataTable.IsAllPiecesFound(APieceIndex: Integer): Boolean;
|
|
begin
|
|
Result := APieceIndex >= GetPieceQuantity;
|
|
end;
|
|
|
|
function TdxSpellCheckerDataTable.CheckDataType(const APiece: PAnsiChar): Boolean;
|
|
var
|
|
ADataIdentifier: PAnsiChar;
|
|
begin
|
|
ADataIdentifier := FDataIdentifier;
|
|
if ADataIdentifier = nil then
|
|
ADataIdentifier := GetDataIdentifier;
|
|
Result := StrLComp(APiece, ADataIdentifier, StrLen(ADataIdentifier)) = 0;
|
|
end;
|
|
|
|
procedure TdxSpellCheckerDataTable.InitializeItem(Index: Integer);
|
|
begin
|
|
// do nothing
|
|
end;
|
|
|
|
function TdxSpellCheckerDataTable.ReadDataHeader(ALine: PAnsiChar): Boolean;
|
|
var
|
|
ATableSize: Integer;
|
|
begin
|
|
Result := ParseHeader(ALine, ATableSize);
|
|
if Result then
|
|
AllocateData(ATableSize);
|
|
end;
|
|
|
|
function TdxSpellCheckerDataTable.ParseHeader(ALine: PAnsiChar; out ATableSize: Integer): Boolean;
|
|
var
|
|
APiece: PAnsiChar;
|
|
begin
|
|
ATableSize := 0;
|
|
APiece := nil;
|
|
Result := GetSecondPartOfString(ALine, APiece);
|
|
if Result then
|
|
begin
|
|
ATableSize := StrInt(APiece);
|
|
StrDispose(APiece);
|
|
end;
|
|
end;
|
|
|
|
function TdxSpellCheckerDataTable.ParseData(AAffixFileManager: TdxHunspellReader): Boolean;
|
|
var
|
|
ADataIndex, APieceIndex: Integer;
|
|
ALineStart, ALineCursor, APiece: PAnsiChar;
|
|
begin
|
|
Result := True;
|
|
for ADataIndex := 0 to Count - 1 do
|
|
begin
|
|
ALineStart := AAffixFileManager.getline;
|
|
try
|
|
RemoveCRLF(ALineStart);
|
|
ALineCursor := ALineStart;
|
|
APieceIndex := 0;
|
|
repeat
|
|
APiece := StrSeparate(@ALineCursor, #0);
|
|
if (APiece <> nil) and (APiece^ <> #0) then
|
|
begin
|
|
Result := AddDataPiece(APiece, ADataIndex, APieceIndex);
|
|
Inc(APieceIndex);
|
|
end;
|
|
until (APiece = nil) or not Result;
|
|
if not IsAllPiecesFound(APieceIndex) then
|
|
begin
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
finally
|
|
StrDispose(ALineStart);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxSpellCheckerDataTable.FreeData;
|
|
begin
|
|
if FData <> nil then
|
|
begin
|
|
FreeDataItems;
|
|
FreeMem(FData, GetDataItemSize * FSize);
|
|
FData := nil;
|
|
end;
|
|
FSize := 0;
|
|
end;
|
|
|
|
{ TdxAffixDataLinkedTable }
|
|
|
|
constructor TdxSpellCheckerDataLinkedTable.Create(AWordBaseManager: TdxHunspellWordBaseManager;
|
|
AAffixManager: TdxHunspellAffixManager);
|
|
begin
|
|
inherited Create;
|
|
FWordBaseManager := AWordBaseManager;
|
|
FAffixManager := AAffixManager;
|
|
end;
|
|
|
|
{ TdxAffixItemTable }
|
|
|
|
constructor TdxAffixItemTable.Create(AWordBaseManager: TdxHunspellWordBaseManager;
|
|
AAffixManager: TdxHunspellAffixManager; AExistentAffixFlags: TdxExistentAffixFlags);
|
|
begin
|
|
inherited Create(AWordBaseManager, AAffixManager);
|
|
FExistentAffixFlags := AExistentAffixFlags;
|
|
end;
|
|
|
|
destructor TdxAffixItemTable.Destroy;
|
|
begin
|
|
StrDispose(FFlag);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TdxAffixItemTable.AddDataPiece(const APiece: PAnsiChar; ADataIndex,
|
|
APieceIndex: Integer): Boolean;
|
|
begin
|
|
Result := inherited AddDataPiece(APiece, ADataIndex, APieceIndex);
|
|
if Result then
|
|
case APieceIndex of
|
|
1: Result := CheckFlag(APiece);
|
|
2: ParseStripString(APiece, ADataIndex);
|
|
3: Result := ParseAppendStringWithAffixes(APiece, ADataIndex);
|
|
4: Result := ParseCondition(APiece, ADataIndex);
|
|
5: Result := ParseMorphologicDescription(APiece, ADataIndex);
|
|
6: AddLineRemainderToMorphologicDescription(APiece, ADataIndex);
|
|
end;
|
|
end;
|
|
|
|
function TdxAffixItemTable.IsAllPiecesFound(APieceIndex: Integer): Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
function TdxAffixItemTable.IsComplexPrefixes: Boolean;
|
|
begin
|
|
Result := FAffixManager.ComplexPrefixes;
|
|
end;
|
|
|
|
procedure TdxAffixItemTable.BuildAffixes;
|
|
begin
|
|
FAffixesIsCreated := True;
|
|
end;
|
|
|
|
function TdxAffixItemTable.GetDataItemSize: Integer;
|
|
begin
|
|
Result := SizeOf(TdxAffixItem);
|
|
end;
|
|
|
|
function TdxAffixItemTable.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
if IsPrefix then
|
|
Result := 'PFX'
|
|
else
|
|
Result := 'SFX';
|
|
end;
|
|
|
|
function TdxAffixItemTable.GetPieceQuantity: Integer;
|
|
begin
|
|
Result := 7;
|
|
end;
|
|
|
|
procedure TdxAffixItemTable.FreeDataItems;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if not FAffixesIsCreated then
|
|
for I := 0 to Count - 1 do
|
|
begin
|
|
StrDispose(Data[I].FStripString);
|
|
StrDispose(Data[I].FAppendString);
|
|
if not HasAffixMorphologicAliases then
|
|
StrDispose(Data[I].FMorphologicalDescription);
|
|
if Data[I].LongCondition then
|
|
StrDispose(Data[I].ConditionSecondPart);
|
|
FreeAndNil(Data[I].FCompatibleFlags);
|
|
end;
|
|
end;
|
|
|
|
function TdxAffixItemTable.ParseHeader(ALine: PAnsiChar; out ATableSize: Integer): Boolean;
|
|
var
|
|
I: Integer;
|
|
APiece: PAnsiChar;
|
|
begin
|
|
Result := True;
|
|
APiece := StrSeparate(@ALine, #0);
|
|
I := 0;
|
|
while (APiece <> nil) and Result and (I < 4) do
|
|
begin
|
|
if APiece^ <> #0 then
|
|
begin
|
|
case I of
|
|
1: Result := ParseFlag(APiece);
|
|
2: ParsePrefixSuffixUnion(APiece);
|
|
3: Result := ParseTableSize(APiece, ATableSize);
|
|
end;
|
|
Inc(I);
|
|
end;
|
|
APiece := StrSeparate(@ALine, #0);
|
|
end;
|
|
end;
|
|
|
|
function TdxAffixItemTable.GetData: PdxAffixItemArray;
|
|
begin
|
|
Result := PdxAffixItemArray(FData);
|
|
end;
|
|
|
|
function TdxAffixItemTable.GetItem(Index: Integer): TdxAffixItem;
|
|
begin
|
|
Result := Data[Index];
|
|
end;
|
|
|
|
procedure TdxAffixItemTable.AddLineRemainderToMorphologicDescription(
|
|
ALine: PAnsiChar; ADataIndex: Integer);
|
|
var
|
|
ANewDescription: PAnsiChar;
|
|
ALength: Integer;
|
|
begin
|
|
if not HasAffixMorphologicAliases then
|
|
begin
|
|
ALength := StrLen(Data[ADataIndex].FMorphologicalDescription) + StrLen(ALine) + 2;
|
|
{$IFDEF DELPHI12}
|
|
ANewDescription := AnsiStrAlloc(ALength);
|
|
{$ELSE}
|
|
ANewDescription := StrAlloc(ALength);
|
|
{$ENDIF}
|
|
StrCopy(ANewDescription, Data[ADataIndex].FMorphologicalDescription);
|
|
ALength := StrLen(ANewDescription);
|
|
StrCopy(ANewDescription + ALength, ' ');
|
|
StrCopy(ANewDescription + ALength + 1, ALine);
|
|
StrDispose(Data[ADataIndex].FMorphologicalDescription);
|
|
Data[ADataIndex].FMorphologicalDescription := ANewDescription;
|
|
end;
|
|
end;
|
|
|
|
function TdxAffixItemTable.CheckFlag(ALine: PAnsiChar): Boolean;
|
|
begin
|
|
Result := (WordBaseManager.DecodeFlag(ALine) = FDecodedFlag) or FlagIsNil;
|
|
end;
|
|
|
|
procedure TdxSuffixItemTable.BuildAffixes;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
inherited BuildAffixes;
|
|
for I := 0 to Count - 1 do
|
|
AffixManager.BuildAffixTree(TdxSuffix.Create(AffixManager, @Data[I],
|
|
FDecodedFlag, GetOptions(Data[I])),
|
|
AffixManager.FSuffixTableArrangedByAppendString, AffixManager.FSuffixTableIndexedByFlag);
|
|
end;
|
|
|
|
function TdxSuffixItemTable.ConditionContainsDuplicateInformation(
|
|
strip: PAnsiChar; stripl: Integer; const ACondition: PAnsiChar; out Contains: Boolean): Boolean;
|
|
var
|
|
AConditionLength, I, J: Integer;
|
|
ANegative, AIsCharactersAgreed: Boolean;
|
|
begin
|
|
Result := True;
|
|
Contains := False;
|
|
AConditionLength := StrLen(ACondition);
|
|
if (stripl >= AConditionLength) and (StrComp(strip + stripl - AConditionLength, ACondition) = 0) then
|
|
Contains := True;
|
|
if not Contains then
|
|
begin
|
|
I := stripl - 1;
|
|
J := AConditionLength - 1;
|
|
while (I >= 0) and (J >= 0) and Result do
|
|
begin
|
|
if (ACondition + J)^ <> ']' then
|
|
begin
|
|
Result := (ACondition + J)^ = (strip + I)^;
|
|
end
|
|
else
|
|
begin
|
|
AIsCharactersAgreed := False;
|
|
repeat
|
|
Dec(J);
|
|
if (strip + I)^ = (ACondition + J)^ then
|
|
AIsCharactersAgreed := True;
|
|
until not((J > 0) and ((ACondition + J)^ <> '['));
|
|
Result := not((J = 0) and ((ACondition + J)^ <> '['));
|
|
if Result then
|
|
begin
|
|
ANegative := (ACondition + J + 1)^ = '^';
|
|
Result := ANegative xor AIsCharactersAgreed;
|
|
end;
|
|
end;
|
|
Dec(I);
|
|
Dec(J);
|
|
end;
|
|
if Result and (J < 0) then
|
|
Contains := True;
|
|
end;
|
|
end;
|
|
|
|
function TdxAffixItemTable.ConditionLength(ALine: PAnsiChar): Integer;
|
|
var
|
|
AInGroup: Boolean;
|
|
begin
|
|
Result := 0;
|
|
AInGroup := False;
|
|
while ALine^ <> #0 do
|
|
begin
|
|
if ALine^ = '[' then
|
|
begin
|
|
AInGroup := True;
|
|
Inc(Result);
|
|
end
|
|
else
|
|
if ALine^ = ']' then
|
|
AInGroup := False
|
|
else
|
|
if not AInGroup then
|
|
Inc(Result);
|
|
Inc(ALine);
|
|
end;
|
|
end;
|
|
|
|
function TdxAffixItemTable.EncodeAffixCondition(ALine: PAnsiChar; ADataIndex: Integer): Boolean;
|
|
begin
|
|
Result := True;
|
|
if StrComp(ALine, '.') <> 0 then
|
|
begin
|
|
Data[ADataIndex].FConditionLength := ConditionLength(ALine);
|
|
StrLCopy(Data[ADataIndex].Condition, ALine, MaxConditionLength);
|
|
if (Data[ADataIndex].Condition[MaxConditionLength - 1] <> #0) and
|
|
((ALine + MaxConditionLength)^ <> #0) then
|
|
begin
|
|
Data[ADataIndex].LongCondition := True;
|
|
Data[ADataIndex].ConditionSecondPart := StrNew(ALine + MaxConditionLength);
|
|
Result := Data[ADataIndex].ConditionSecondPart <> nil;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
Data[ADataIndex].FConditionLength := 0;
|
|
Data[ADataIndex].Condition[0] := #0;
|
|
end;
|
|
end;
|
|
|
|
function TdxAffixItemTable.HasAffixFlagAliases: Boolean;
|
|
begin
|
|
Result := WordBaseManager.HasAffixFlagAliases;
|
|
end;
|
|
|
|
function TdxAffixItemTable.HasAffixMorphologicAliases: Boolean;
|
|
begin
|
|
Result := WordBaseManager.HasAffixMorphologicAliases;
|
|
end;
|
|
|
|
function TdxAffixItemTable.FlagIsNil: Boolean;
|
|
var
|
|
AEncodedFlag: PAnsiChar;
|
|
begin
|
|
AEncodedFlag := WordBaseManager.EncodeFlag(FDecodedFlag);
|
|
try
|
|
Result := AEncodedFlag = nil;
|
|
finally
|
|
StrDispose(AEncodedFlag);
|
|
end;
|
|
end;
|
|
|
|
function TdxAffixItemTable.FlagIsUnique(AFlag: Word): Boolean;
|
|
begin
|
|
Result := IsPrefix and (FExistentAffixFlags[FDecodedFlag] and ExistentPrefixFlag = 0) or
|
|
(FExistentAffixFlags[FDecodedFlag] and ExistentSuffixFlag = 0);
|
|
end;
|
|
|
|
procedure TdxAffixItemTable.FreeIfZero(var AString: TdxStringData);
|
|
begin
|
|
if StrComp(AString.Data, '0') = 0 then
|
|
begin
|
|
StrDispose(AString.Data);
|
|
AString.Data := StrNew(PAnsiChar(''));
|
|
AString.Length := 0;
|
|
end;
|
|
end;
|
|
|
|
function TdxAffixItemTable.GetOptions(AItem: TdxAffixItem): ShortInt;
|
|
begin
|
|
Result := 0;
|
|
if FPrefixSuffixUnion then
|
|
Result := Result + aoPrefixSuffixUnion;
|
|
if HasAffixFlagAliases then
|
|
Result := Result + aoAffixFlagAliasTable;
|
|
if WordBaseManager.HasAffixMorphologicAliases then
|
|
Result := Result + aoAffixMorphologyTable;
|
|
if AItem.LongCondition then
|
|
Result := Result + aeLONGCOND;
|
|
end;
|
|
|
|
function TdxAffixItemTable.IsReverseWritingDirection: Boolean;
|
|
begin
|
|
Result := AffixManager.ComplexPrefixes;
|
|
end;
|
|
|
|
procedure TdxAffixItemTable.ParseAppendString(const ALine: PAnsiChar; ADataIndex: Integer);
|
|
begin
|
|
ProcessIgnoreChars(ALine);
|
|
ProcessReverseString(ALine);
|
|
Data[ADataIndex].FAppendString := StrNew(ALine);
|
|
end;
|
|
|
|
function TdxAffixItemTable.ParseAppendStringWithAffixes(const ALine: PAnsiChar; ADataIndex: Integer): Boolean;
|
|
var
|
|
ACompatibleFlagCursor: PAnsiChar;
|
|
ATempStringData: TdxStringData;
|
|
begin
|
|
Result := True;
|
|
ACompatibleFlagCursor := StrScan(ALine, '/');
|
|
if ACompatibleFlagCursor <> nil then
|
|
begin
|
|
ACompatibleFlagCursor^ := #0;
|
|
|
|
ParseAppendString(ALine, ADataIndex);
|
|
|
|
Result := ParseCompatibleFlags(ACompatibleFlagCursor + 1, ADataIndex);
|
|
|
|
ACompatibleFlagCursor^ := '/';
|
|
|
|
if Result then
|
|
RegisterCompatibleFlags(ADataIndex);
|
|
end
|
|
else
|
|
ParseAppendString(ALine, ADataIndex);
|
|
|
|
Data[ADataIndex].FAppendStringLength := StrLen(Data[ADataIndex].FAppendString);
|
|
if Result then
|
|
begin
|
|
ATempStringData.Data := Data[ADataIndex].FAppendString;
|
|
ATempStringData.Length := Data[ADataIndex].FAppendStringLength;
|
|
FreeIfZero(ATempStringData);
|
|
Data[ADataIndex].FAppendString := ATempStringData.Data;
|
|
Data[ADataIndex].FAppendStringLength := ATempStringData.Length;
|
|
end;
|
|
end;
|
|
|
|
function TdxAffixItemTable.ParseCompatibleFlags(const ALine: PAnsiChar; ADataIndex: Integer): Boolean;
|
|
begin
|
|
Result := True;
|
|
Data[ADataIndex].FCompatibleFlags := TdxHunspellFlags.Create(FWordBaseManager);
|
|
if HasAffixFlagAliases then
|
|
Result := Data[ADataIndex].FCompatibleFlags.InitializeByAlias(ALine)
|
|
else
|
|
begin
|
|
Data[ADataIndex].FCompatibleFlags.Decode(ALine);
|
|
Data[ADataIndex].FCompatibleFlags.Sort;
|
|
end;
|
|
end;
|
|
|
|
function TdxAffixItemTable.ParseCondition(ALine: PAnsiChar; ADataIndex: Integer): Boolean;
|
|
var
|
|
Contains: Boolean;
|
|
begin
|
|
Result := True;
|
|
ProcessReverseString(ALine);
|
|
if IsReverseWritingDirection then
|
|
ReverseCondition(ALine);
|
|
if (Data[ADataIndex].FStripStringLength <> 0) and (StrComp(ALine, '.') <> 0) then
|
|
begin
|
|
Result := ConditionContainsDuplicateInformation(Data[ADataIndex].FStripString,
|
|
Data[ADataIndex].FStripStringLength, ALine, Contains);
|
|
if Result and Contains then
|
|
StrPCopy(ALine, '.');
|
|
end;
|
|
if Result then
|
|
begin
|
|
if not IsPrefix then
|
|
begin
|
|
StrReverse(ALine);
|
|
ReverseCondition(ALine);
|
|
end;
|
|
Result := EncodeAffixCondition(ALine, ADataIndex);
|
|
end;
|
|
end;
|
|
|
|
function TdxAffixItemTable.ParseFlag(ALine: PAnsiChar): Boolean;
|
|
begin
|
|
FDecodedFlag := WordBaseManager.DecodeFlag(ALine);
|
|
Result := FlagIsUnique(FDecodedFlag);
|
|
if Result then
|
|
begin
|
|
SetExisting;
|
|
FFlag := StrNew(ALine);
|
|
end;
|
|
end;
|
|
|
|
function TdxAffixItemTable.ParseMorphologicDescription(ALine: PAnsiChar; ADataIndex: Integer): Boolean;
|
|
begin
|
|
Result := True;
|
|
if HasAffixMorphologicAliases then
|
|
Data[ADataIndex].FMorphologicalDescription := WordBaseManager.GetAffixMorphologyByAlias(StrInt(ALine))
|
|
else
|
|
begin
|
|
ProcessReverseString(ALine);
|
|
Data[ADataIndex].FMorphologicalDescription := StrNew(ALine);
|
|
Result := Data[ADataIndex].FMorphologicalDescription <> nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxAffixItemTable.ParsePrefixSuffixUnion(ALine: PAnsiChar);
|
|
begin
|
|
FPrefixSuffixUnion := ALine^ = 'Y';
|
|
end;
|
|
|
|
procedure TdxAffixItemTable.ParseStripString(const ALine: PAnsiChar; ADataIndex: Integer);
|
|
var
|
|
ATempStringData: TdxStringData;
|
|
begin
|
|
ProcessReverseString(ALine);
|
|
ATempStringData.Data := StrNew(ALine);
|
|
ATempStringData.Length := StrLen(ATempStringData.Data);
|
|
FreeIfZero(ATempStringData);
|
|
Data[ADataIndex].FStripString := ATempStringData.Data;
|
|
Data[ADataIndex].FStripStringLength := ATempStringData.Length;
|
|
end;
|
|
|
|
function TdxAffixItemTable.ParseTableSize(ALine: PAnsiChar; out ATableSize: Integer): Boolean;
|
|
begin
|
|
ATableSize := StrInt(ALine);
|
|
Result := (ATableSize <> 0) or FlagIsNil;
|
|
end;
|
|
|
|
procedure TdxAffixItemTable.ProcessIgnoreChars(ALine: PAnsiChar);
|
|
begin
|
|
if AffixManager.Ignore <> nil then
|
|
RemoveIgnoredChars(ALine, AffixManager.Ignore);
|
|
end;
|
|
|
|
procedure TdxAffixItemTable.ProcessReverseString(ALine: PAnsiChar);
|
|
begin
|
|
if IsReverseWritingDirection then
|
|
StrReverse(ALine);
|
|
end;
|
|
|
|
procedure TdxAffixItemTable.RegisterCompatibleFlags(ADataIndex: Integer);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
AffixManager.CompatibleFlagsExist := True;
|
|
for I := 0 to Data[ADataIndex].FCompatibleFlags.Length - 1 do
|
|
AffixManager.SetCompatibleFlags(Data[ADataIndex].FCompatibleFlags[I], True);
|
|
end;
|
|
|
|
procedure TdxAffixItemTable.ReverseCondition(ACondition: PAnsiChar);
|
|
var
|
|
ANegative: Boolean;
|
|
AConditionCursor: PAnsiChar;
|
|
begin
|
|
ANegative := False;
|
|
AConditionCursor := ACondition + StrLen(ACondition) - 1;
|
|
while AConditionCursor >= ACondition do
|
|
begin
|
|
case AConditionCursor^ of
|
|
'[': begin
|
|
if ANegative then
|
|
(AConditionCursor + 1)^ := '['
|
|
else
|
|
AConditionCursor^ := ']';
|
|
end;
|
|
']': begin
|
|
AConditionCursor^ := '[';
|
|
if ANegative then
|
|
(AConditionCursor + 1)^ := '^';
|
|
ANegative := False;
|
|
end;
|
|
'^': begin
|
|
if (AConditionCursor + 1)^ = ']' then
|
|
ANegative := True
|
|
else
|
|
(AConditionCursor + 1)^ := AConditionCursor^;
|
|
end;
|
|
else
|
|
if ANegative then
|
|
(AConditionCursor + 1)^ := AConditionCursor^;
|
|
end;
|
|
Dec(AConditionCursor);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxAffixItemTable.SetExisting;
|
|
begin
|
|
if IsPrefix then
|
|
FExistentAffixFlags[FDecodedFlag] := FExistentAffixFlags[FDecodedFlag] or ExistentPrefixFlag
|
|
else
|
|
FExistentAffixFlags[FDecodedFlag] := FExistentAffixFlags[FDecodedFlag] or ExistentSuffixFlag;
|
|
end;
|
|
|
|
{ TdxPrefixItemTable }
|
|
|
|
procedure TdxPrefixItemTable.BuildAffixes;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
inherited BuildAffixes;
|
|
for I := 0 to Count - 1 do
|
|
AffixManager.BuildAffixTree(TdxPrefix.Create(AffixManager, @Data[I],
|
|
FDecodedFlag, GetOptions(Data[I])),
|
|
AffixManager.FPrefixTableArrangedByAppendString, AffixManager.FPrefixTableIndexedByFlag);
|
|
end;
|
|
|
|
function TdxPrefixItemTable.ConditionContainsDuplicateInformation(
|
|
strip: PAnsiChar; stripl: Integer; const ACondition: PAnsiChar; out Contains: Boolean): Boolean;
|
|
var
|
|
AConditionLength, I, J: Integer;
|
|
ANegative, AIsCharactersAgreed: Boolean;
|
|
begin
|
|
Result := True;
|
|
Contains := False;
|
|
AConditionLength := StrLen(ACondition);
|
|
if StrComp(strip, ACondition) = 0 then
|
|
Contains := True;
|
|
if not Contains then
|
|
begin
|
|
I := 0;
|
|
J := 0;
|
|
while (I < stripl) and (J < AConditionLength) and Result do
|
|
begin
|
|
if (ACondition + J)^ <> '[' then
|
|
begin
|
|
Result := (ACondition + J)^ = (strip + I)^;
|
|
end
|
|
else
|
|
begin
|
|
ANegative := (ACondition + J + 1)^ = '^';
|
|
AIsCharactersAgreed := False;
|
|
repeat
|
|
Inc(J);
|
|
if (strip + I)^ = (ACondition + J)^ then
|
|
AIsCharactersAgreed := True;
|
|
until not((J < AConditionLength - 1) and ((ACondition + J)^ <> ']'));
|
|
Result := not((J = AConditionLength - 1) and ((ACondition + J)^ <> ']'));
|
|
if Result then
|
|
Result := ANegative xor AIsCharactersAgreed;
|
|
end;
|
|
Inc(I);
|
|
Inc(J);
|
|
end;
|
|
if Result and (J >= AConditionLength) then
|
|
Contains := True;
|
|
end;
|
|
end;
|
|
|
|
function TdxPrefixItemTable.IsPrefix: Boolean;
|
|
begin
|
|
Result := not IsComplexPrefixes;
|
|
end;
|
|
|
|
{ TdxSuffixItemTable }
|
|
|
|
function TdxSuffixItemTable.IsPrefix: Boolean;
|
|
begin
|
|
Result := IsComplexPrefixes;
|
|
end;
|
|
|
|
{ TdxBreakTable }
|
|
|
|
constructor TdxBreakTable.Create;
|
|
begin
|
|
inherited Create;
|
|
FillDefaultData;
|
|
end;
|
|
|
|
procedure TdxBreakTable.FillDefaultData;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
I := 3;
|
|
AllocateData(I);
|
|
Data[I - 3] := StrNew('-');
|
|
Data[I - 2] := StrNew('^-');
|
|
Data[I - 1] := StrNew('-$');
|
|
end;
|
|
|
|
function TdxBreakTable.AddDataPiece(const APiece: PAnsiChar; ADataIndex,
|
|
APieceIndex: Integer): Boolean;
|
|
begin
|
|
Result := inherited AddDataPiece(APiece, ADataIndex, APieceIndex);
|
|
if Result and (APieceIndex = 1) then
|
|
Data[ADataIndex] := StrNew(APiece);
|
|
end;
|
|
|
|
procedure TdxBreakTable.FreeDataItems;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to Count - 1 do
|
|
begin
|
|
StrDispose(Data[I]);
|
|
Data[I] := nil;
|
|
end;
|
|
end;
|
|
|
|
function TdxBreakTable.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := 'BREAK';
|
|
end;
|
|
|
|
function TdxBreakTable.GetDataItemSize: Integer;
|
|
begin
|
|
Result := SizeOf(PAnsiChar);
|
|
end;
|
|
|
|
function TdxBreakTable.GetPieceQuantity: Integer;
|
|
begin
|
|
Result := 2;
|
|
end;
|
|
|
|
function TdxBreakTable.GetData: PdxPAnsiCharArray;
|
|
begin
|
|
Result := PdxPAnsiCharArray(FData);
|
|
end;
|
|
|
|
function TdxBreakTable.GetItem(Index: Integer): PAnsiChar;
|
|
begin
|
|
Result := Data[Index];
|
|
end;
|
|
|
|
{ TdxCheckCompoundPatternTable }
|
|
|
|
function TdxCheckCompoundPatternTable.AddDataPiece(const APiece: PAnsiChar;
|
|
ADataIndex, APieceIndex: Integer): Boolean;
|
|
begin
|
|
Result := inherited AddDataPiece(APiece, ADataIndex, APieceIndex);
|
|
if Result then
|
|
case APieceIndex of
|
|
1: begin
|
|
Data[ADataIndex].Pattern := StrNew(APiece);
|
|
ExtractCondition(Data[ADataIndex].Pattern, Data[ADataIndex].Condition);
|
|
end;
|
|
2: begin
|
|
Data[ADataIndex].Pattern2 := StrNew(APiece);
|
|
ExtractCondition(Data[ADataIndex].Pattern2, Data[ADataIndex].Condition2);
|
|
end;
|
|
3: begin
|
|
Data[ADataIndex].Pattern3 := StrNew(APiece);
|
|
FIsSimplified := True;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxCheckCompoundPatternTable.FreeDataItems;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to Count - 1 do
|
|
begin
|
|
StrDispose(Data[I].Pattern);
|
|
StrDispose(Data[I].Pattern2);
|
|
StrDispose(Data[I].Pattern3);
|
|
end;
|
|
end;
|
|
|
|
function TdxCheckCompoundPatternTable.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diCheckCompoundPattern;
|
|
end;
|
|
|
|
function TdxCheckCompoundPatternTable.GetDataItemSize: Integer;
|
|
begin
|
|
Result := SizeOf(TdxCompoundForbidPattern);
|
|
end;
|
|
|
|
function TdxCheckCompoundPatternTable.GetPieceQuantity: Integer;
|
|
begin
|
|
Result := 3;
|
|
end;
|
|
|
|
procedure TdxCheckCompoundPatternTable.InitializeItem(Index: Integer);
|
|
begin
|
|
Data[Index].Pattern := nil;
|
|
Data[Index].Pattern2 := nil;
|
|
Data[Index].Pattern3 := nil;
|
|
Data[Index].Condition := NullFlag;
|
|
Data[Index].Condition2 := NullFlag;
|
|
end;
|
|
|
|
procedure TdxCheckCompoundPatternTable.ExtractCondition(APattern: PAnsiChar;
|
|
var ACondition: Word);
|
|
var
|
|
ADelimiter: PAnsiChar;
|
|
begin
|
|
ADelimiter := StrScan(APattern, '/');
|
|
if ADelimiter <> nil then
|
|
begin
|
|
ADelimiter^ := #0;
|
|
ACondition := WordBaseManager.DecodeFlag(ADelimiter + 1);
|
|
end;
|
|
end;
|
|
|
|
function TdxCheckCompoundPatternTable.GetData: PdxCompoundForbidPatternArray;
|
|
begin
|
|
Result := PdxCompoundForbidPatternArray(FData);
|
|
end;
|
|
|
|
function TdxCheckCompoundPatternTable.GetItem(Index: Integer): TdxCompoundForbidPattern;
|
|
begin
|
|
Result := Data[Index];
|
|
end;
|
|
|
|
{ TdxCompoundRuleTable }
|
|
|
|
function TdxCompoundRuleTable.AddDataPiece(const APiece: PAnsiChar; ADataIndex,
|
|
APieceIndex: Integer): Boolean;
|
|
begin
|
|
Result := inherited AddDataPiece(APiece, ADataIndex, APieceIndex);
|
|
if Result and (APieceIndex = 1) then
|
|
Result := ParseFlags(APiece, ADataIndex);
|
|
end;
|
|
|
|
procedure TdxCompoundRuleTable.FreeDataItems;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to Count - 1 do
|
|
FreeMem(Data[I].Pattern, Data[I].Count * SizeOf(Word));
|
|
end;
|
|
|
|
function TdxCompoundRuleTable.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diCompoundRule;
|
|
end;
|
|
|
|
function TdxCompoundRuleTable.GetDataItemSize: Integer;
|
|
begin
|
|
Result := SizeOf(TdxCompoundFlag);
|
|
end;
|
|
|
|
function TdxCompoundRuleTable.GetPieceQuantity: Integer;
|
|
begin
|
|
Result := 2;
|
|
end;
|
|
|
|
procedure TdxCompoundRuleTable.InitializeItem(Index: Integer);
|
|
begin
|
|
Data[Index].Pattern := nil;
|
|
end;
|
|
|
|
function TdxCompoundRuleTable.GetData: PdxCompoundFlagArray;
|
|
begin
|
|
Result := PdxCompoundFlagArray(FData);
|
|
end;
|
|
|
|
function TdxCompoundRuleTable.GetItem(Index: Integer): TdxCompoundFlag;
|
|
begin
|
|
Result := Data[Index];
|
|
end;
|
|
|
|
function TdxCompoundRuleTable.ParseFlags(APiece: PAnsiChar; AIndex: Integer): Boolean;
|
|
var
|
|
ABracketPosition: PAnsiChar;
|
|
AIsEndOfLine: Boolean;
|
|
AItem: PdxCompoundFlag;
|
|
|
|
procedure AllocPattern(AItem: PdxCompoundFlag; ASize: Integer);
|
|
begin
|
|
AItem^.Count := ASize;
|
|
AItem^.Pattern := AllocMem(AItem^.Count * SizeOf(Word));
|
|
end;
|
|
|
|
procedure ReadFlags(APiece: PAnsiChar; AItem: PdxCompoundFlag);
|
|
var
|
|
AFlags: TdxHunspellFlags;
|
|
I: Integer;
|
|
begin
|
|
AFlags := TdxHunspellFlags.Create(FWordBaseManager);
|
|
try
|
|
AFlags.Decode(APiece);
|
|
for I := 0 to AFlags.Length - 1 do
|
|
begin
|
|
AItem^.Pattern[AItem^.Length] := AFlags[I];
|
|
Inc(AItem^.Length);
|
|
end;
|
|
finally
|
|
AFlags.Free;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
AItem := @Data[AIndex];
|
|
AllocPattern(AItem, StrLen(APiece));
|
|
if StrScan(APiece, '(') <> nil then
|
|
begin
|
|
AIsEndOfLine := False;
|
|
repeat
|
|
ABracketPosition := APiece + 1;
|
|
while (ABracketPosition^ <> '(') and (ABracketPosition^ <> ')') and (ABracketPosition^ <> #0) do
|
|
Inc(ABracketPosition);
|
|
if ABracketPosition^ = #0 then
|
|
AIsEndOfLine := True
|
|
else
|
|
ABracketPosition^ := #0;
|
|
if APiece^ = '(' then
|
|
Inc(APiece);
|
|
if (APiece^ = '*') or (APiece^ = '?') then
|
|
begin
|
|
AItem^.Pattern[AItem^.Length] := Ord(APiece^);
|
|
Inc(AItem^.Length);
|
|
end
|
|
else
|
|
if APiece^ <> #0 then
|
|
ReadFlags(APiece, AItem);
|
|
APiece := ABracketPosition + 1;
|
|
until AIsEndOfLine;
|
|
end
|
|
else
|
|
ReadFlags(APiece, AItem);
|
|
Result := AItem^.Length <> 0;
|
|
end;
|
|
|
|
{ TdxMapTable }
|
|
|
|
function TdxMapTable.AddDataPiece(const APiece: PAnsiChar; ADataIndex,
|
|
APieceIndex: Integer): Boolean;
|
|
begin
|
|
Result := inherited AddDataPiece(APiece, ADataIndex, APieceIndex);
|
|
if Result and (APieceIndex = 1) then
|
|
begin
|
|
Data[ADataIndex].CharacterSet := StrNew(APiece);
|
|
Data[ADataIndex].Length := StrLen(Data[ADataIndex].CharacterSet);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxMapTable.FreeDataItems;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to Count - 1 do
|
|
StrDispose(Data[I].CharacterSet);
|
|
end;
|
|
|
|
function TdxMapTable.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diMap;
|
|
end;
|
|
|
|
function TdxMapTable.GetDataItemSize: Integer;
|
|
begin
|
|
Result := SizeOf(TdxMapTableItem);
|
|
end;
|
|
|
|
function TdxMapTable.GetPieceQuantity: Integer;
|
|
begin
|
|
Result := 2;
|
|
end;
|
|
|
|
procedure TdxMapTable.InitializeItem(Index: Integer);
|
|
begin
|
|
Data[Index].CharacterSet := nil;
|
|
Data[Index].Length := 0;
|
|
end;
|
|
|
|
function TdxMapTable.GetData: PdxMapArray;
|
|
begin
|
|
Result := PdxMapArray(FData);
|
|
end;
|
|
|
|
function TdxMapTable.GetItem(Index: Integer): TdxMapTableItem;
|
|
begin
|
|
Result := Data[Index];
|
|
end;
|
|
|
|
{ TdxReplaceTable }
|
|
|
|
function TdxReplaceTable.AddDataPiece(const APiece: PAnsiChar; ADataIndex,
|
|
APieceIndex: Integer): Boolean;
|
|
begin
|
|
Result := inherited AddDataPiece(APiece, ADataIndex, APieceIndex);
|
|
if Result then
|
|
case APieceIndex of
|
|
1: Data[ADataIndex].Initial := StrReplace(StrNew(APiece), '_', ' ');
|
|
2: Data[ADataIndex].Replacement := StrReplace(StrNew(APiece), '_', ' ');
|
|
end;
|
|
end;
|
|
|
|
procedure TdxReplaceTable.FreeDataItems;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to Count - 1 do
|
|
begin
|
|
StrDispose(Data[I].Initial);
|
|
StrDispose(Data[I].Replacement);
|
|
end;
|
|
end;
|
|
|
|
function TdxReplaceTable.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diRep;
|
|
end;
|
|
|
|
function TdxReplaceTable.GetDataItemSize: Integer;
|
|
begin
|
|
Result := SizeOf(TdxReplaceTableItem);
|
|
end;
|
|
|
|
function TdxReplaceTable.GetPieceQuantity: Integer;
|
|
begin
|
|
Result := 3;
|
|
end;
|
|
|
|
procedure TdxReplaceTable.InitializeItem(Index: Integer);
|
|
begin
|
|
Data[Index].Initial := nil;
|
|
Data[Index].Replacement := nil;
|
|
end;
|
|
|
|
function TdxReplaceTable.GetData: PdxReplaceArray;
|
|
begin
|
|
Result := PdxReplaceArray(FData);
|
|
end;
|
|
|
|
function TdxReplaceTable.GetItem(Index: Integer): TdxReplaceTableItem;
|
|
begin
|
|
Result := Data[Index];
|
|
end;
|
|
|
|
{ TdxSortedReplaceTable }
|
|
|
|
function TdxSortedReplaceTable.conv(const Aword: PAnsiChar; dest: PAnsiChar): Integer;
|
|
var
|
|
stl, I, n, l: Integer;
|
|
pc: PAnsiChar;
|
|
begin
|
|
Result := 0;
|
|
if Data = nil then
|
|
Exit;
|
|
stl := 0;
|
|
I := 0;
|
|
while I < Length(AWord) do
|
|
begin
|
|
n := near1(Aword + I);
|
|
l := match(Aword + I, n);
|
|
if l <> 0 then
|
|
begin
|
|
pc := Data[n].Replacement;
|
|
StrCopy(dest + stl, pc);
|
|
Inc(stl, Length(pc));
|
|
Inc(I, l - 1);
|
|
Result := 1;
|
|
end
|
|
else
|
|
begin
|
|
(dest + stl)^ := (Aword + I)^;
|
|
Inc(stl);
|
|
end;
|
|
Inc(I);
|
|
end;
|
|
(dest + stl)^ := #0;
|
|
end;
|
|
|
|
function TdxSortedReplaceTable.AddDataPiece(const APiece: PAnsiChar; ADataIndex,
|
|
APieceIndex: Integer): Boolean;
|
|
begin
|
|
Result := inherited AddDataPiece(APiece, ADataIndex, APieceIndex);
|
|
if Result and (APieceIndex = 2) then
|
|
Sort(ADataIndex);
|
|
end;
|
|
|
|
function TdxSortedReplaceTable.match(const Aword: PAnsiChar; n: Integer): Integer;
|
|
var
|
|
P: TdxReplaceTableItem;
|
|
begin
|
|
Result := 0;
|
|
P := Data[n];
|
|
if StrLComp(Aword, P.Initial, Length(P.Initial)) = 0 then
|
|
Result := Length(P.Initial);
|
|
end;
|
|
|
|
function TdxSortedReplaceTable.near1(const Aword: PAnsiChar): Integer;
|
|
var
|
|
p1, p2, m, c: Integer;
|
|
begin
|
|
p1 := 0;
|
|
p2 := Count;
|
|
while p2 - p1 > 1 do
|
|
begin
|
|
m := Round((p1 + p2) / 2);
|
|
c := StrComp(Aword, Data[m].Initial);
|
|
if c <= 0 then
|
|
begin
|
|
p2 := m;
|
|
if c = 0 then
|
|
p1 := m;
|
|
end
|
|
else
|
|
p1 := m;
|
|
end;
|
|
Result := p1;
|
|
end;
|
|
|
|
procedure TdxSortedReplaceTable.Sort(AIndex: Integer);
|
|
var
|
|
I: Integer;
|
|
AItem: TdxReplaceTableItem;
|
|
begin
|
|
for I := AIndex downto 1 do
|
|
begin
|
|
AItem := Data[I];
|
|
if StrComp(AItem.Initial, Data[I - 1].Initial) < 0 then
|
|
begin
|
|
Data[I] := Data[I - 1];
|
|
Data[I - 1] := AItem;
|
|
end
|
|
else
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
{ TAffixFileReader }
|
|
|
|
constructor TAffixFileReader.Create(AAffixManager: TdxHunspellAffixManager);
|
|
begin
|
|
FAffixManager := AAffixManager;
|
|
end;
|
|
|
|
function TAffixFileReader.ParseFlag(ALine: PAnsiChar; var ADecodedFlag: Word;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
var
|
|
AFlag: PAnsiChar;
|
|
begin
|
|
Result := True;
|
|
AFlag := nil;
|
|
if (ADecodedFlag <> NullFlag) and not(ADecodedFlag >= DEFAULTFLAGS) then
|
|
begin
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
if not GetSecondPartOfString(ALine, AFlag) then
|
|
begin
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
ADecodedFlag := FAffixManager.FWordBaseManager.DecodeFlag(AFlag);
|
|
StrDispose(AFlag);
|
|
end;
|
|
|
|
function TAffixFileReader.ParseNumber(ALine: PAnsiChar; out ANumber: Integer): Boolean;
|
|
var
|
|
ASecondPart: PAnsiChar;
|
|
begin
|
|
Result := True;
|
|
if ANumber <> - 1 then
|
|
begin
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
ASecondPart := nil;
|
|
try
|
|
if GetSecondPartOfString(ALine, ASecondPart) then
|
|
ANumber := StrInt(ASecondPart)
|
|
else
|
|
Result := False;
|
|
finally
|
|
StrDispose(ASecondPart);
|
|
end;
|
|
end;
|
|
|
|
{ TTryReader }
|
|
|
|
function TTryReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diTry;
|
|
end;
|
|
|
|
function TTryReader.Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := GetSecondPartOfString(ALine, FAffixManager.FTryChars);
|
|
end;
|
|
|
|
{ TSetReader }
|
|
|
|
function TSetReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diSet;
|
|
end;
|
|
|
|
function TSetReader.Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean;
|
|
var
|
|
AEncoding: PAnsiChar;
|
|
begin
|
|
AEncoding := nil;
|
|
try
|
|
Result := GetSecondPartOfString(ALine, AEncoding);
|
|
FAffixManager.CodePage := GetCodePageByName(AEncoding);
|
|
if Result and (StrComp(AEncoding, 'UTF-8') = 0) then //TODO:
|
|
//TODO:
|
|
// FAffixManager.FIsUTF8 := 1;
|
|
raise Exception.Create('UTF-8 doesn''t supported');
|
|
finally
|
|
StrDispose(AEncoding);
|
|
end;
|
|
end;
|
|
|
|
{ TComplexPrefixesReader }
|
|
|
|
function TComplexPrefixesReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diComplexPrefixes;
|
|
end;
|
|
|
|
function TComplexPrefixesReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := True;
|
|
FAffixManager.FComplexPrefixes := True;
|
|
end;
|
|
|
|
{ TCompoundFlagReader }
|
|
|
|
function TCompoundFlagReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diCompoundFlag;
|
|
end;
|
|
|
|
function TCompoundFlagReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := ParseFlag(ALine, FAffixManager.FCompoundFlag, AReader);
|
|
end;
|
|
|
|
{ TCompoundBeginReader }
|
|
|
|
function TCompoundBeginReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diCompoundBegin;
|
|
end;
|
|
|
|
function TCompoundBeginReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
if FAffixManager.FComplexPrefixes then
|
|
Result := ParseFlag(ALine, FAffixManager.FCompoundEnd, AReader)
|
|
else
|
|
Result := ParseFlag(ALine, FAffixManager.FCompoundBegin, AReader);
|
|
end;
|
|
|
|
{ TCompoundEndReader }
|
|
|
|
function TCompoundEndReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diCompoundEnd;
|
|
end;
|
|
|
|
function TCompoundEndReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
if FAffixManager.FComplexPrefixes then
|
|
Result := ParseFlag(ALine, FAffixManager.FCompoundBegin, AReader)
|
|
else
|
|
Result := ParseFlag(ALine, FAffixManager.FCompoundEnd, AReader);
|
|
end;
|
|
|
|
{ TCompoundMiddleReader }
|
|
|
|
function TCompoundMiddleReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diCompoundMiddle;
|
|
end;
|
|
|
|
function TCompoundMiddleReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := ParseFlag(ALine, FAffixManager.FCompoundMiddle, AReader);
|
|
end;
|
|
|
|
{ TCompoundWordMaxReader }
|
|
|
|
function TCompoundWordMaxReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diCompoundWordMax;
|
|
end;
|
|
|
|
function TCompoundWordMaxReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := ParseNumber(ALine, FAffixManager.FCompoundWordMax);
|
|
end;
|
|
|
|
{ TCompoundRootReader }
|
|
|
|
function TCompoundRootReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diCompoundRoot;
|
|
end;
|
|
|
|
function TCompoundRootReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := ParseFlag(ALine, FAffixManager.FCompoundRoot, AReader);
|
|
end;
|
|
|
|
{ TCompoundPermitFlagReader }
|
|
|
|
function TCompoundPermitFlagReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diCompoundPermitFlag;
|
|
end;
|
|
|
|
function TCompoundPermitFlagReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := ParseFlag(ALine, FAffixManager.FCompoundPermitFlag, AReader);
|
|
end;
|
|
|
|
{ TCompoundForbidFlagReader }
|
|
|
|
function TCompoundForbidFlagReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diCompoundForbidFlag;
|
|
end;
|
|
|
|
function TCompoundForbidFlagReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := ParseFlag(ALine, FAffixManager.FCompoundForbidFlag, AReader);
|
|
end;
|
|
|
|
{ TCheckCompoundDupReader }
|
|
|
|
function TCheckCompoundDupReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diCheckCompoundDup;
|
|
end;
|
|
|
|
function TCheckCompoundDupReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := True;
|
|
FAffixManager.FCheckCompoundDup := True;
|
|
end;
|
|
|
|
{ TCheckCompoundRepReader }
|
|
|
|
function TCheckCompoundRepReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diCheckCompoundRep;
|
|
end;
|
|
|
|
function TCheckCompoundRepReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := True;
|
|
FAffixManager.FCheckCompoundRep := True;
|
|
end;
|
|
|
|
{ TCheckCompoundTripleReader }
|
|
|
|
function TCheckCompoundTripleReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diCheckCompoundTriple;
|
|
end;
|
|
|
|
function TCheckCompoundTripleReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := True;
|
|
FAffixManager.FCheckCompoundTriple := True;
|
|
end;
|
|
|
|
{ TSimplifiedTripleReader }
|
|
|
|
function TSimplifiedTripleReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diSimplifiedTriple;
|
|
end;
|
|
|
|
function TSimplifiedTripleReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := True;
|
|
FAffixManager.FSimplifiedTriple := True;
|
|
end;
|
|
|
|
{ TCheckCompoundCaseReader }
|
|
|
|
function TCheckCompoundCaseReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diCheckCompoundCase;
|
|
end;
|
|
|
|
function TCheckCompoundCaseReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := True;
|
|
FAffixManager.FCheckCompoundCase := True;
|
|
end;
|
|
|
|
{ TNoSuggestReader }
|
|
|
|
function TNoSuggestReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diNoSuggest;
|
|
end;
|
|
|
|
function TNoSuggestReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := ParseFlag(ALine, FAffixManager.FNoSuggest, AReader);
|
|
end;
|
|
|
|
{ TForbiddenWordReader }
|
|
|
|
function TForbiddenWordReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diForbiddenWord;
|
|
end;
|
|
|
|
function TForbiddenWordReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := ParseFlag(ALine, FAffixManager.FForbiddenWord, AReader);
|
|
end;
|
|
|
|
{ TLemmaPresentReader }
|
|
|
|
function TLemmaPresentReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diLemmaPresent;
|
|
end;
|
|
|
|
function TLemmaPresentReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := ParseFlag(ALine, FAffixManager.FLemmaPresent, AReader);
|
|
end;
|
|
|
|
{ TCircumfixReader }
|
|
|
|
function TCircumfixReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diCircumfix;
|
|
end;
|
|
|
|
function TCircumfixReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := ParseFlag(ALine, FAffixManager.FCircumfix, AReader);
|
|
end;
|
|
|
|
{ TOnlyInCompoundReader }
|
|
|
|
function TOnlyInCompoundReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diOnlyInCompound;
|
|
end;
|
|
|
|
function TOnlyInCompoundReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := ParseFlag(ALine, FAffixManager.FOnlyInCompound, AReader);
|
|
end;
|
|
|
|
{ TPseudoRootReader }
|
|
|
|
function TPseudoRootReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diPseudoRoot;
|
|
end;
|
|
|
|
function TPseudoRootReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := ParseFlag(ALine, FAffixManager.FNeedAffix, AReader)
|
|
end;
|
|
|
|
{ TNeedAffixReader }
|
|
|
|
function TNeedAffixReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diNeedAffix;
|
|
end;
|
|
|
|
function TNeedAffixReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := ParseFlag(ALine, FAffixManager.FNeedAffix, AReader);
|
|
end;
|
|
|
|
{ TCompoundMinReader }
|
|
|
|
function TCompoundMinReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diCompoundMin;
|
|
end;
|
|
|
|
function TCompoundMinReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := ParseNumber(ALine, FAffixManager.FCompoundPartMin);
|
|
if FAffixManager.FCompoundPartMin < 1 then
|
|
FAffixManager.FCompoundPartMin := 1;
|
|
end;
|
|
|
|
{ TCompoundSyllableReader }
|
|
|
|
function TCompoundSyllableReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diCompoundSyllable;
|
|
end;
|
|
|
|
function TCompoundSyllableReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := FAffixManager.ParseCompoundSyllable(ALine, AReader);
|
|
end;
|
|
|
|
{ TSyllableNumReader }
|
|
|
|
function TSyllableNumReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diSyllableNum;
|
|
end;
|
|
|
|
function TSyllableNumReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := GetSecondPartOfString(ALine, FAffixManager.FSyllableNum);
|
|
end;
|
|
|
|
{ TWordCharsReader }
|
|
|
|
function TWordCharsReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diWordChars;
|
|
end;
|
|
|
|
function TWordCharsReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := False; //TODO:
|
|
end;
|
|
|
|
{ TIgnoreReader }
|
|
|
|
function TIgnoreReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diIgnore;
|
|
end;
|
|
|
|
function TIgnoreReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := ParseArray(ALine, FAffixManager.FIgnore, FAffixManager.IsUTF8);
|
|
end;
|
|
|
|
{ TRepReader }
|
|
|
|
function TRepReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diRep;
|
|
end;
|
|
|
|
function TRepReader.Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := FAffixManager.ParseRep(ALine, AReader);
|
|
end;
|
|
|
|
{ TIConvReader }
|
|
|
|
function TIConvReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diIConv;
|
|
end;
|
|
|
|
function TIConvReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := FAffixManager.FInputReplaceTable.ReadData(ALine, AReader);
|
|
end;
|
|
|
|
{ TOConvReader }
|
|
|
|
function TOConvReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diOConv;
|
|
end;
|
|
|
|
function TOConvReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := FAffixManager.FOutputReplaceTable.ReadData(ALine, AReader);
|
|
end;
|
|
|
|
{ TCheckCompoundPatternReader }
|
|
|
|
function TCheckCompoundPatternReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diCheckCompoundPattern;
|
|
end;
|
|
|
|
function TCheckCompoundPatternReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := FAffixManager.FCheckCompoundPatternTable.ReadData(ALine, AReader);
|
|
end;
|
|
|
|
{ TCompoundRuleReader }
|
|
|
|
function TCompoundRuleReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diCompoundRule;
|
|
end;
|
|
|
|
function TCompoundRuleReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := FAffixManager.FCompoundRuleTable.ReadData(ALine, AReader);
|
|
end;
|
|
|
|
{ TMapReader }
|
|
|
|
function TMapReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diMap;
|
|
end;
|
|
|
|
function TMapReader.Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := FAffixManager.FMapTable.ReadData(ALine, AReader);
|
|
end;
|
|
|
|
{ TBreakReader }
|
|
|
|
function TBreakReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diBreak;
|
|
end;
|
|
|
|
function TBreakReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := FAffixManager.FBreakTable.ReadData(ALine, AReader);
|
|
end;
|
|
|
|
{ TLangReader }
|
|
|
|
function TLangReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diLang;
|
|
end;
|
|
|
|
function TLangReader.Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean;
|
|
var
|
|
ALanguage: PAnsiChar;
|
|
begin
|
|
ALanguage := nil;
|
|
try
|
|
Result := GetSecondPartOfString(ALine, ALanguage);
|
|
if Result then
|
|
FAffixManager.FLanguage := GetLanguageID(ALanguage);
|
|
finally
|
|
StrDispose(ALanguage);
|
|
end;
|
|
end;
|
|
|
|
{ TVersionReader }
|
|
|
|
function TVersionReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diVersion;
|
|
end;
|
|
|
|
function TVersionReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := True;
|
|
ALine := ALine + 7;
|
|
while (ALine^ = ' ') or (ALine^ = #9) do
|
|
Inc(ALine);
|
|
if ALine^ <> #0 then
|
|
FAffixManager.FVersion := StrNew(ALine)
|
|
else
|
|
FAffixManager.FVersion := nil;
|
|
end;
|
|
|
|
{ TNoSplitSugsReader }
|
|
|
|
function TNoSplitSugsReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diNoSplitSugs;
|
|
end;
|
|
|
|
function TNoSplitSugsReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := True;
|
|
FAffixManager.FNoSplitSugs := True;
|
|
end;
|
|
|
|
{ TFullStripReader }
|
|
|
|
function TFullStripReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diFullStrip;
|
|
end;
|
|
|
|
function TFullStripReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := True;
|
|
FAffixManager.FFullStrip := True;
|
|
end;
|
|
|
|
{ TSugsWithDotsReader }
|
|
|
|
function TSugsWithDotsReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diSugsWithDots;
|
|
end;
|
|
|
|
function TSugsWithDotsReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := True;
|
|
FAffixManager.FSugsWithDots := True;
|
|
end;
|
|
|
|
{ TKeepCaseReader }
|
|
|
|
function TKeepCaseReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diKeepCase;
|
|
end;
|
|
|
|
function TKeepCaseReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := ParseFlag(ALine, FAffixManager.FKeepcase, AReader);
|
|
end;
|
|
|
|
{ TSubStandardReader }
|
|
|
|
function TSubStandardReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diSubStandard;
|
|
end;
|
|
|
|
function TSubStandardReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := ParseFlag(ALine, FAffixManager.FSubstandard, AReader);
|
|
end;
|
|
|
|
{ TCheckSharpsReader }
|
|
|
|
function TCheckSharpsReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diCheckSharps;
|
|
end;
|
|
|
|
function TCheckSharpsReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
begin
|
|
Result := True;
|
|
FAffixManager.FCheckSharps := 1;
|
|
end;
|
|
|
|
{ TPrefixReader }
|
|
|
|
function TPrefixReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diPrefix;
|
|
end;
|
|
|
|
function TPrefixReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
var
|
|
AAffixType: TdxAffixType;
|
|
begin
|
|
AAffixType := atPrefix;
|
|
if FAffixManager.FComplexPrefixes then
|
|
AAffixType := atSuffix;
|
|
Result := FAffixManager.DoAffixParsing(ALine, AReader, AAffixType);
|
|
end;
|
|
|
|
{ TSuffixReader }
|
|
|
|
function TSuffixReader.GetDataIdentifier: PAnsiChar;
|
|
begin
|
|
Result := diSuffix;
|
|
end;
|
|
|
|
function TSuffixReader.Process(ALine: PAnsiChar;
|
|
AReader: TdxHunspellReader): Boolean;
|
|
var
|
|
AAffixType: TdxAffixType;
|
|
begin
|
|
AAffixType := atSuffix;
|
|
if FAffixManager.FComplexPrefixes then
|
|
AAffixType := atPrefix;
|
|
Result := FAffixManager.DoAffixParsing(ALine, AReader, AAffixType);
|
|
end;
|
|
|
|
end.
|