LazUtils: Add case-insensitive functions PosI(), LazStartsText() and LazEndsText().

git-svn-id: trunk@64503 -
This commit is contained in:
juha 2021-02-08 19:09:17 +00:00
parent 5fe23e9ae8
commit bd875ab2f5
5 changed files with 92 additions and 45 deletions

View File

@ -187,7 +187,7 @@ begin
inc(p);
if p>fHtmlLen then break;
if fHTML[p]='=' then
AttrName:=UpperCase(copy(fHTML,Start,p-Start));
AttrName:=copy(fHTML,Start,p-Start);
end;
// Attribute "value"
if fHTML[p]='"' then
@ -197,7 +197,7 @@ begin
while (p<=fHtmlLen) and (fHTML[p]<>'"') do
inc(p);
if p>fHtmlLen then break;
AttrValue:=UpperCase(copy(fHTML,Start,p-Start));
AttrValue:=copy(fHTML,Start,p-Start);
end;
inc(p);
if (fHTML[p-1]='>') then break; // end of tag
@ -214,7 +214,8 @@ begin
AddNewLine;
'DIV':
begin
fInDivTitle:=(AttrName='CLASS') and (AttrValue='TITLE');
fInDivTitle:=(CompareText(AttrName,'CLASS')=0)
and (CompareText(AttrValue,'TITLE')=0);
if fInDivTitle then
begin
AddNewLine;

View File

@ -583,12 +583,9 @@ begin
end;
function TLazLoggerLogGroupList.IndexOf(const AConfigName: String): integer;
var
s: String;
begin
Result := Count - 1;
s := UpperCase(AConfigName);
while (Result >= 0) and (Item[Result]^.ConfigName <> s) do
while (Result >= 0) and (CompareText(Item[Result]^.ConfigName, AConfigName) <> 0) do
dec(Result);
end;

View File

@ -37,6 +37,9 @@ type
const
EndOfLine: shortstring = LineEnding;
function PosI(const SubStr, S: string): integer;
function LazStartsText(const ASubText, AText: string): Boolean;
function LazEndsText(const ASubText, AText: string): Boolean;
function IsNumber(s: String): Boolean;
// Functions for line endings
@ -111,6 +114,61 @@ const
implementation
function PosI(const SubStr, S: string): integer;
// A case-insensitive version of Pos().
// Note: StrUtils has ContainsText but its implementation is VERY slow.
var
Len1, Len2, Cnt1, Cnt2: integer;
SubFirst: Char;
begin
Len1 := Length(SubStr);
Len2 := Length(S);
if (Len1 = 0) or (Len1 > Len2) then
Exit(0);
SubFirst := LowerCase(SubStr[1]);
Result := 0;
for Cnt1 := 1 to Len2-Len1+1 do
begin // Outer loop finds the first matching character.
if LowerCase(S[Cnt1]) = SubFirst then
begin // Maybe a start of the substring.
Result := Cnt1;
for Cnt2 := 2 to Len1 do
if LowerCase(S[Cnt1+Cnt2-1]) <> LowerCase(SubStr[Cnt2]) then
begin
Result := 0; // No match
break;
end;
end;
if Result > 0 then
break;
end;
end;
function LazStartsText(const ASubText, AText: string): Boolean;
// A fast implementation of StartsText.
// The version in RTL calls AnsiCompareText and is VERY slow.
begin
if (Length(AText) >= Length(ASubText)) and (ASubText <> '') then
Result := StrLIComp(PChar(ASubText), PChar(AText), Length(ASubText)) = 0
else
Result := False;
end;
function LazEndsText(const ASubText, AText: string): Boolean;
// A fast implementation of StartsText.
// The version in RTL calls AnsiCompareText and is VERY slow.
var
LS, LT: SizeInt;
begin
LS := Length(ASubText);
LT := Length(AText);
if (LT >= LS) and (ASubText <> '') then
Result := StrLIComp(PChar(ASubText), @AText[LT-LS+1], LS) = 0
else
Result := False;
end;
function IsNumber(s: String): Boolean;
var
i: Integer;
@ -1096,7 +1154,7 @@ function GetPart(const ASkipTo, AnEnd: array of String; var ASource: String;
const AnIgnoreCase: Boolean = False; const AnUpdateSource: Boolean = True): String;
var
n, i, idx: Integer;
S, Source, Match: String;
Source, Match: String;
HasEscape: Boolean;
begin
Source := ASource;
@ -1106,9 +1164,6 @@ begin
idx := 0;
Match := '';
HasEscape := False;
if AnIgnoreCase
then S := UpperCase(Source)
else S := Source;
for n := Low(ASkipTo) to High(ASkipTo) do
begin
if ASkipTo[n] = ''
@ -1117,33 +1172,26 @@ begin
Continue;
end;
if AnIgnoreCase
then i := Pos(UpperCase(ASkipTo[n]), S)
else i := Pos(ASkipTo[n], S);
then i := PosI(ASkipTo[n], Source)
else i := Pos(ASkipTo[n], Source);
if i > idx
then begin
idx := i;
Match := ASkipTo[n];
end;
end;
if (idx = 0) and not HasEscape
then begin
Result := '';
Exit;
end;
if (idx = 0) and not HasEscape then Exit('');
if idx > 0
then Delete(Source, 1, idx + Length(Match) - 1);
end;
if AnIgnoreCase
then S := UpperCase(Source)
else S := Source;
idx := MaxInt;
for n := Low(AnEnd) to High(AnEnd) do
begin
if AnEnd[n] = '' then Continue;
if AnIgnoreCase
then i := Pos(UpperCase(AnEnd[n]), S)
else i := Pos(AnEnd[n], S);
then i := PosI(AnEnd[n], Source)
else i := Pos(AnEnd[n], Source);
if (i > 0) and (i < idx) then idx := i;
end;
@ -1277,30 +1325,29 @@ end;
function StringCase(const AString: String; const ACase: array of String; const AIgnoreCase, APartial: Boolean): Integer;
var
Search, S: String;
S: String;
begin
if High(ACase) = -1
then begin
Result := -1;
Exit;
end;
if AIgnoreCase
then Search := UpperCase(AString)
else Search := AString;
if High(ACase) = -1 then Exit(-1);
for Result := Low(ACase) to High(ACase) do
begin
if AIgnoreCase
then S := UpperCase(ACase[Result])
else S := ACase[Result];
if Search = S then Exit;
S := ACase[Result];
// Exact match
if AIgnoreCase then begin
if CompareText(AString, S) = 0 then Exit;
end
else begin
if AString = S then Exit;
end;
if not APartial then Continue;
if Length(Search) >= Length(S) then Continue;
if StrLComp(PChar(Search), PChar(S), Length(Search)) = 0 then Exit;
if Length(AString) >= Length(S) then Continue;
// Partial match
if AIgnoreCase then begin
if StrLIComp(PChar(AString), PChar(S), Length(AString)) = 0 then Exit;
end
else begin
if StrLComp(PChar(AString), PChar(S), Length(AString)) = 0 then Exit;
end;
end;
Result := -1;
end;

View File

@ -541,7 +541,7 @@ begin
inc(I);
if not (Path[I] in AllowDirectorySeparators) then
Exit('');
if UpperCase(Copy(Path, I + 1, 3)) = 'UNC' then
if CompareText(Copy(Path, I+1, 3), 'UNC') = 0 then
begin
inc(I, 4);
if I < Len then

View File

@ -33,6 +33,8 @@ uses
Classes, SysUtils, contnrs, Math, dateutils, laz.VirtualTrees,
// LCL
Controls, Graphics, Menus, Dialogs, Forms, LCLType, Buttons,
// LazUtils
LazStringUtils,
// IDEIntf
LCLIntf, PackageIntf,
// OpkMan
@ -941,7 +943,7 @@ procedure TVisualTree.FilterTree(const AFilterBy: TFilterBy; const AText:
var
P: Integer;
begin
P := Pos(UpperCase(AText), UpperCase(ADataText));
P := PosI(AText, ADataText);
if P > 0 then
FVST.IsVisible[Node] := True
else
@ -987,7 +989,7 @@ begin
begin
if Data^.DataType = 12 then
begin
if Pos(UpperCase(CategoriesEng[AExtraParam]), UpperCase(Data^.Category)) > 0 then
if PosI(CategoriesEng[AExtraParam], Data^.Category) > 0 then
FilterNode(Node, 'PackageCategory')
else
FilterNode(Node, '')