mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-21 09:58:13 +00:00
ADD: More flexible quicksearch for chineses(Pinyin,Wubi,Shuangpin …) (#131)
This commit is contained in:
parent
f4361dd451
commit
10f403f579
5 changed files with 99 additions and 25 deletions
|
|
@ -640,7 +640,7 @@ begin
|
|||
else
|
||||
begin
|
||||
// Match the file name and Pinyin letter
|
||||
if aMasks.Matches(AFile.Name) or aMasks.Matches(MakeSpellCode(AFile.Name)) then
|
||||
if aMasks.Matches(AFile.Name, True) then
|
||||
Result := False;
|
||||
end;
|
||||
end
|
||||
|
|
|
|||
|
|
@ -694,7 +694,7 @@ begin
|
|||
sFileName := AFile.Name;
|
||||
|
||||
// Match the file name and Pinyin letter
|
||||
if not (Masks.Matches(sFileName) or (Masks.Matches(MakeSpellCode(sFileName)))) then
|
||||
if not (Masks.Matches(sFileName, True)) then
|
||||
Result := False;
|
||||
|
||||
if Result then
|
||||
|
|
|
|||
67
src/uPinyin.pas
Normal file
67
src/uPinyin.pas
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
unit uPinyin;
|
||||
|
||||
interface
|
||||
|
||||
type
|
||||
pinyinarray=array[0..20901] of word;
|
||||
|
||||
function PinyinMatch(a,b:UnicodeChar):boolean;
|
||||
|
||||
implementation
|
||||
|
||||
Uses sysutils;
|
||||
|
||||
var
|
||||
PINYINTABLE: pinyinarray;
|
||||
PINYINTABLELOADED: boolean = False;
|
||||
|
||||
procedure loadPinyinTable;
|
||||
var
|
||||
f:file of pinyinarray;
|
||||
tblpath:string;
|
||||
begin
|
||||
if PINYINTABLELOADED then exit;
|
||||
tblpath := ExtractFilePath(Paramstr(0)) + 'tcmatch.tbl';
|
||||
if fileexists(tblpath) then
|
||||
begin
|
||||
Assign(f, tblpath);
|
||||
try
|
||||
Reset(f);
|
||||
seek(f,0);
|
||||
Read(f, PINYINTABLE);
|
||||
PINYINTABLELOADED := True;
|
||||
finally
|
||||
close(f);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function PinyinMatch(a,b:UnicodeChar):boolean;
|
||||
var
|
||||
i,code:word;
|
||||
j:byte;
|
||||
begin
|
||||
loadPinyinTable;
|
||||
PinyinMatch := True;
|
||||
|
||||
if a = b then exit;
|
||||
|
||||
if PINYINTABLELOADED then
|
||||
begin
|
||||
if (Ord(a) >= 19968) and (Ord(a) < 40869) then
|
||||
begin
|
||||
i := Ord(a) - 19968;
|
||||
code := PINYINTABLE[i];
|
||||
j := code and 31;
|
||||
if(j > 0) and (j+96 = Ord(b)) then exit;
|
||||
j := code >> 5 and 31;
|
||||
if(j > 0) and (j+96 = Ord(b)) then exit;
|
||||
j := code >> 10 and 31;
|
||||
if(j > 0) and (j+96 = Ord(b)) then exit;
|
||||
end;
|
||||
end;
|
||||
|
||||
PinyinMatch := False;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
|
@ -53,9 +53,9 @@ type
|
|||
procedure Update;
|
||||
public
|
||||
constructor Create(const AValue: string; bCaseSensitive: boolean = False; bIgnoreAccents: boolean = False; bWindowsInterpretation: boolean = False);
|
||||
function Matches(const AFileName: string): boolean;
|
||||
function LegacyMatches(const AFileName: string): boolean;
|
||||
function WindowsMatches(const AFileName: string): boolean;
|
||||
function Matches(const AFileName: string; usePinyin: boolean = False): boolean;
|
||||
function LegacyMatches(const AFileName: string; usePinyin: boolean = False): boolean;
|
||||
function WindowsMatches(const AFileName: string; usePinyin: boolean = False): boolean;
|
||||
property CaseSensitive:boolean read FCaseSensitive write SetCaseSence;
|
||||
property Template:string read FTemplate write SetTemplate;
|
||||
end;
|
||||
|
|
@ -76,14 +76,14 @@ type
|
|||
constructor Create(const AValue: string; ASeparatorCharset: string = ';'; bCaseSensitive: boolean = False; bIgnoreAccents: boolean = False; bWindowsInterpretation: boolean = False);
|
||||
destructor Destroy; override;
|
||||
|
||||
function Matches(const AFileName: String): Boolean;
|
||||
function Matches(const AFileName: String; usePinyin:boolean=False): Boolean;
|
||||
|
||||
property Count: Integer read GetCount;
|
||||
property Items[Index: Integer]: TMask read GetItem;
|
||||
end;
|
||||
|
||||
function MatchesMask(const FileName, Mask: String; CaseSensitive: Boolean = False): Boolean;
|
||||
function MatchesMaskList(const FileName, Mask: string; ASeparatorCharset: string = ';'; ACaseSensitive: boolean = False; AIgnoreAccents: boolean = False; AWindowsInterpretation: boolean = False): boolean;
|
||||
function MatchesMask(const FileName, Mask: String; CaseSensitive: Boolean = False; usePinyin:boolean=False): Boolean;
|
||||
function MatchesMaskList(const FileName, Mask: string; ASeparatorCharset: string = ';'; ACaseSensitive: boolean = False; AIgnoreAccents: boolean = False; AWindowsInterpretation: boolean = False; usePinyin:boolean=False): boolean;
|
||||
|
||||
|
||||
implementation
|
||||
|
|
@ -93,11 +93,11 @@ uses
|
|||
LazUTF8,
|
||||
|
||||
//DC
|
||||
uAccentsUtils;
|
||||
uPinyin, uAccentsUtils;
|
||||
|
||||
|
||||
{ MatchesMask }
|
||||
function MatchesMask(const FileName, Mask: String; CaseSensitive: Boolean = False): Boolean;
|
||||
function MatchesMask(const FileName, Mask: String; CaseSensitive: Boolean = False; usePinyin:boolean=False ): Boolean;
|
||||
var
|
||||
AMask: TMask;
|
||||
begin
|
||||
|
|
@ -105,7 +105,7 @@ begin
|
|||
begin
|
||||
AMask := TMask.Create(Mask, CaseSensitive);
|
||||
try
|
||||
Result := AMask.Matches(FileName);
|
||||
Result := AMask.Matches(FileName, usePinyin);
|
||||
finally
|
||||
AMask.Free;
|
||||
end;
|
||||
|
|
@ -115,7 +115,7 @@ begin
|
|||
end;
|
||||
|
||||
{ MatchesMaskList }
|
||||
function MatchesMaskList(const FileName, Mask: string; ASeparatorCharset: string; ACaseSensitive: boolean = False; AIgnoreAccents: boolean = False; AWindowsInterpretation: boolean = False): boolean;
|
||||
function MatchesMaskList(const FileName, Mask: string; ASeparatorCharset: string; ACaseSensitive: boolean = False; AIgnoreAccents: boolean = False; AWindowsInterpretation: boolean = False; usePinyin:boolean=False): boolean;
|
||||
var
|
||||
AMaskList: TMaskList;
|
||||
begin
|
||||
|
|
@ -123,7 +123,7 @@ begin
|
|||
begin
|
||||
AMaskList := TMaskList.Create(Mask, ASeparatorCharset, ACaseSensitive, AIgnoreAccents, AWindowsInterpretation);
|
||||
try
|
||||
Result := AMaskList.Matches(FileName);
|
||||
Result := AMaskList.Matches(FileName, usePinyin);
|
||||
finally
|
||||
AMaskList.Free;
|
||||
end;
|
||||
|
|
@ -236,7 +236,7 @@ begin
|
|||
end;
|
||||
|
||||
{ TMask.Matches }
|
||||
function TMask.Matches(const AFileName: string): boolean;
|
||||
function TMask.Matches(const AFileName: string; usePinyin: boolean = False): boolean;
|
||||
var
|
||||
sFilename: string;
|
||||
begin
|
||||
|
|
@ -251,13 +251,13 @@ begin
|
|||
sFilename := UTF8LowerCase(sFilename);
|
||||
|
||||
if not fWindowsInterpretation then
|
||||
Result := LegacyMatches(sFileName)
|
||||
Result := LegacyMatches(sFileName, usePinyin)
|
||||
else
|
||||
Result := WindowsMatches(sFileName);
|
||||
Result := WindowsMatches(sFileName, usePinyin);
|
||||
end;
|
||||
|
||||
{ TMask.LegacyMatches }
|
||||
function TMask.LegacyMatches(const AFileName: string): boolean;
|
||||
function TMask.LegacyMatches(const AFileName: string; usePinyin: boolean = False): boolean;
|
||||
var
|
||||
L: Integer;
|
||||
S: UnicodeString;
|
||||
|
|
@ -275,7 +275,14 @@ var
|
|||
begin
|
||||
if CharIndex > L then Exit;
|
||||
//DCDebug('Match ' + S[CharIndex] + '<?>' + FMask.Chars[I].CharValue);
|
||||
if S[CharIndex] <> FMask.Chars[I].CharValue then Exit;
|
||||
if usePinyin then
|
||||
begin
|
||||
if not PinyinMatch(S[CharIndex], FMask.Chars[I].CharValue) then exit;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if S[CharIndex] <> FMask.Chars[I].CharValue then Exit;
|
||||
end;
|
||||
Inc(CharIndex);
|
||||
end;
|
||||
mcAnyChar:
|
||||
|
|
@ -326,7 +333,7 @@ end;
|
|||
// *. -> any file without extension ( .foo is a filename without extension according to Windows)
|
||||
// foo. matches only foo but not foo.txt
|
||||
// foo.* -> match either foo or foo.*
|
||||
function TMask.WindowsMatches(const AFileName: string): boolean;
|
||||
function TMask.WindowsMatches(const AFileName: string; usePinyin: boolean = False): boolean;
|
||||
var
|
||||
Ext, sInitialTemplate: string;
|
||||
sInitialMask: UnicodeString;
|
||||
|
|
@ -339,7 +346,7 @@ begin
|
|||
sInitialTemplate := FTemplate; //Preserve initial state of FTemplate
|
||||
FTemplate := Copy(sInitialMask, 1, Length(sInitialMask) - 2);
|
||||
Update;
|
||||
Result := LegacyMatches(AFileName);
|
||||
Result := LegacyMatches(AFileName, usePinyin);
|
||||
FTemplate := sInitialTemplate; //Restore initial state of FTemplate
|
||||
Update;
|
||||
end
|
||||
|
|
@ -353,7 +360,7 @@ begin
|
|||
sInitialTemplate := FTemplate; //Preserve initial state of FTemplate
|
||||
FTemplate := Copy(sInitialMask, 1, Length(sInitialMask) - 1);
|
||||
Update;
|
||||
Result := LegacyMatches(AFileName);
|
||||
Result := LegacyMatches(AFileName, usePinyin);
|
||||
FTemplate := sInitialTemplate; //Restore initial state of FTemplate
|
||||
Update;
|
||||
end
|
||||
|
|
@ -366,11 +373,11 @@ begin
|
|||
begin
|
||||
//First see if we have 'foo'
|
||||
Result := (AFileName = Copy(sInitialMask, 1, Length(sInitialMask) - 2));
|
||||
if not Result then Result := LegacyMatches(AFileName);
|
||||
if not Result then Result := LegacyMatches(AFileName, usePinyin);
|
||||
end
|
||||
else
|
||||
begin
|
||||
Result := LegacyMatches(AFileName); //all other cases just call LegacyMatches()
|
||||
Result := LegacyMatches(AFileName, usePinyin); //all other cases just call LegacyMatches()
|
||||
end;
|
||||
end;
|
||||
|
||||
|
|
@ -436,7 +443,7 @@ begin
|
|||
end;
|
||||
|
||||
{ TMaskList.Matches }
|
||||
function TMaskList.Matches(const AFileName: string): boolean;
|
||||
function TMaskList.Matches(const AFileName: string; usePinyin:boolean=False): boolean;
|
||||
var
|
||||
I: integer;
|
||||
begin
|
||||
|
|
@ -444,7 +451,7 @@ begin
|
|||
|
||||
for I := 0 to FMasks.Count - 1 do
|
||||
begin
|
||||
if TMask(FMasks.Items[I]).Matches(AFileName) then
|
||||
if TMask(FMasks.Items[I]).Matches(AFileName, usePinyin) then
|
||||
begin
|
||||
Result := True;
|
||||
Exit;
|
||||
|
|
|
|||
BIN
tcmatch.tbl
Normal file
BIN
tcmatch.tbl
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue