LazUtils: Optimize PosI(), the case-insensitive version of Pos().

git-svn-id: trunk@64616 -
This commit is contained in:
juha 2021-02-18 12:28:20 +00:00
parent 0d468e1564
commit 350c9735d0
2 changed files with 26 additions and 25 deletions

View File

@ -423,7 +423,7 @@ begin
Dec(ExtLen); Dec(ExtLen);
end; end;
if ExtLen <> FnExtLen then if ExtLen <> FnExtLen then
exit(False); // Ext has different length than Filename exit(False); // Ext has different length than Filename's extension
// compare extensions // compare extensions
if CaseSensitive then if CaseSensitive then
Result := StrLComp(ExtP, FnP, ExtLen) = 0 Result := StrLComp(ExtP, FnP, ExtLen) = 0
@ -460,7 +460,7 @@ begin
Dec(ExtLen); Dec(ExtLen);
end; end;
if ExtLen <> FnExtLen then if ExtLen <> FnExtLen then
continue; // Ext has different length than Filename continue; // Ext has different length than Filename's extension
// compare extensions // compare extensions
if CaseSensitive then if CaseSensitive then
Result := StrLComp(ExtP, FnP, ExtLen) = 0 Result := StrLComp(ExtP, FnP, ExtLen) = 0

View File

@ -138,32 +138,33 @@ end;
{$ENDIF} {$ENDIF}
function PosI(const SubStr, S: string): integer; function PosI(const SubStr, S: string): integer;
// A case-insensitive version of Pos(). // A case-insensitive optimized version of Pos(). Comparison Supports only ASCII.
// Note: StrUtils has ContainsText but its implementation is VERY slow. // Can be used instead of common but slower Pos(UpperCase(SubStr),UpperCase(S));
var var
Len1, Len2, Cnt1, Cnt2: integer; SubLen, SLen: integer;
SubFirst: Char; SubP, SP, SPEnd: PChar;
SubBP: PByte absolute SubP;
SBP: PByte absolute SP;
begin begin
Len1 := Length(SubStr);
Len2 := Length(S);
if (Len1 = 0) or (Len1 > Len2) then
Exit(0);
SubFirst := LowerCase(SubStr[1]);
Result := 0; Result := 0;
for Cnt1 := 1 to Len2-Len1+1 do SubLen := Length(SubStr);
begin // Outer loop finds the first matching character. SLen := Length(S);
if LowerCase(S[Cnt1]) = SubFirst then if (SubLen = 0) or (SubLen > SLen) then
begin // Maybe a start of the substring. Exit;
Result := Cnt1; SubP := @SubStr[1];
for Cnt2 := 2 to Len1 do SP := @S[1];
if LowerCase(S[Cnt1+Cnt2-1]) <> LowerCase(SubStr[Cnt2]) then SPEnd := SP + SLen - SubLen;
begin while True do
Result := 0; // No match begin
break; while (SP <= SPEnd) and ((SubBP^ xor SBP^) and $DF <> 0) do
end; Inc(SP); // Not equal even after removing the $20 upper/lower diff
end; if SP > SPEnd then
if Result > 0 then Break;
break; // Now they may be equal but could be false positive
if (Char(SBP^ and $DF) in ['A'..'Z']) or (SP^ = SubP^) then
if StrLIComp(SubP+1, SP+1, SubLen-1) = 0 then // First char matched
Exit(SP - @S[1] + 1); // .. and also the rest of it
Inc(SP);
end; end;
end; end;