📄 jclstrings.pas
字号:
function StrCompareRange(const S1, S2: AnsiString; const Index, Count: Integer): Integer; assembler;
asm
TEST EAX, EAX
JZ @@Str1Null
TEST EDX, EDX
JZ @@StrNull
DEC ECX
JS @@StrNull
PUSH EBX
PUSH ESI
PUSH EDI
MOV EBX, Count
DEC EBX
JS @@NoWork
MOV ESI, EAX
MOV EDI, EDX
MOV EDX, [ESI - AnsiStrRecSize].TAnsiStrRec.Length
// # of chars in S1 - (Index - 1)
SUB EDX, ECX
JLE @@NoWork
// # of chars in S1 - (Count - 1)
SUB EDX, EBX
JLE @@NoWork
// move to index'th char
ADD ESI, ECX
MOV ECX, [EDI - AnsiStrRecSize].TAnsiStrRec.Length
DEC ECX
JS @@NoWork
// if Length(S2) > Count then ECX := Count else ECX := Length(S2)
CMP ECX, EBX
JLE @@Skip1
MOV ECX, EBX
@@Skip1:
XOR EAX, EAX
XOR EDX, EDX
@@Loop:
MOV AL, [ESI]
INC ESI
MOV DL, [EDI]
INC EDI
CMP AL, DL
JNE @@MisMatch
DEC ECX
JGE @@Loop
@@Match:
XOR EAX, EAX
POP EDI
POP ESI
POP EBX
JMP @@Exit
@@MisMatch:
SUB EAX, EDX
POP EDI
POP ESI
POP EBX
JMP @@Exit
@@NoWork:
MOV EAX, -2
POP EDI
POP ESI
POP EBX
JMP @@Exit
@@Str1Null:
MOV EAX, 0
TEST EDX, EDX
JZ @@Exit
@@StrNull:
MOV EAX, -1
@@Exit:
end;
function StrFillChar(const C: AnsiChar; const Count: Integer): AnsiString;
begin
Assert(Count >= 0);
SetLength(Result, Count);
if (Count > 0) then
FillChar(Result[1], Count, Ord(C));
end;
function StrFind(const Substr, S: AnsiString; const Index: Integer): Integer; assembler;
const
SearchChar: Byte = 0;
NumberOfChars: Integer = 0;
asm
// if SubStr = '' then Return := 0;
TEST EAX, EAX
JZ @@SubstrIsNull
// if Str = '' then Return := 0;
TEST EDX, EDX
JZ @@StrIsNull
// Index := Index - 1; if Index < 0 then Return := 0;
DEC ECX
JL @@IndexIsSmall
// EBX will hold the case table, ESI pointer to Str, EDI pointer
// to Substr and - # of chars in Substr to compare
PUSH EBX
PUSH ESI
PUSH EDI
// set the string pointers
MOV ESI, EDX
MOV EDI, EAX
// save the Index in EDX
MOV EDX, ECX
// temporary get the length of Substr and Str
MOV EBX, [EDI - AnsiStrRecSize].TAnsiStrRec.Length
MOV ECX, [ESI - AnsiStrRecSize].TAnsiStrRec.Length
// save the address of Str to compute the result
PUSH ESI
// dec the length of Substr because the first char is brought out of it
DEC EBX
JS @@NotFound
// #positions in Str to look at = Length(Str) - Length(Substr) - Index - 2
SUB ECX, EBX
JLE @@NotFound
SUB ECX, EDX
JLE @@NotFound
// # of chars in Substr to compare
MOV NumberOfChars, EBX
// point Str to Index'th char
ADD ESI, EDX
// load case map into EBX, and clear EAX
LEA EBX, AnsiCaseMap
XOR EAX, EAX
XOR EDX, EDX
// bring the first char out of the Substr and point Substr to the next char
MOV DL, [EDI]
INC EDI
// lower case it
MOV DL, [EBX + EDX]
MOV SearchChar, DL
JMP @@Find
@@FindNext:
// update the loop counter and check the end of AnsiString.
// if we reached the end, Substr was not found.
DEC ECX
JL @@NotFound
@@Find:
// get current char from the AnsiString, and point Str to the next one
MOV AL, [ESI]
INC ESI
// lower case current char
MOV AL, [EBX + EAX]
// does current char match primary search char? if not, go back to the main loop
CMP AL, SearchChar
JNE @@FindNext
@@Compare:
// # of chars in Substr to compare
MOV EDX, NumberOfChars
@@CompareNext:
// dec loop counter and check if we reached the end. If yes then we found it
DEC EDX
JL @@Found
// get the chars from Str and Substr, if they are equal then continue comparing
MOV AL, [ESI + EDX]
CMP AL, [EDI + EDX]
JE @@CompareNext
// otherwise try the reverse case. If they still don't match go back to the Find loop
MOV AL, [EBX + EAX + AnsiReOffset]
CMP AL, [EDI + EDX]
JNE @@FindNext
// if they matched, continue comparing
JMP @@CompareNext
@@Found:
// we found it, calculate the result
MOV EAX, ESI
POP ESI
SUB EAX, ESI
POP EDI
POP ESI
POP EBX
RET
@@NotFound:
// not found it, clear the result
XOR EAX, EAX
POP ESI
POP EDI
POP ESI
POP EBX
RET
@@IndexIsSmall:
@@StrIsNull:
// clear the result
XOR EAX, EAX
@@SubstrIsNull:
@@Exit:
end;
function StrHasPrefix(const S: AnsiString; const Prefixes: array of string): Boolean;
begin
Result := StrPrefixIndex(S, Prefixes) > -1;
end;
function StrIndex(const S: AnsiString; const List: array of AnsiString): Integer;
var
I: Integer;
begin
Result := -1;
for I := Low(List) to High(List) do
begin
if AnsiSameText(S, List[I]) then
begin
Result := I;
Break;
end;
end;
end;
function StrILastPos(const SubStr, S: AnsiString): Integer;
begin
Result := JclStrings.StrLastPos(StrUpper(SubStr), StrUpper(S));
end;
function StrIPos(const SubStr, S: AnsiString): integer;
begin
Result := Pos(AnsiUpperCase(SubStr), AnsiUpperCase(S));
end;
function StrIsOneOf(const S: AnsiString; const List: array of AnsiString): Boolean;
begin
Result := StrIndex(S, List) > -1;
end;
function StrLastPos(const SubStr, S: AnsiString): Integer;
var
Last, Current: PAnsiChar;
begin
Result := 0;
Last := nil;
Current := PAnsiChar(S);
while (Current <> nil) and (Current^ <> #0) do
begin
Current := AnsiStrPos(PAnsiChar(Current), PAnsiChar(SubStr));
if Current <> nil then
begin
Last := Current;
Inc(Current);
end;
end;
if Last <> nil then
Result := Abs((Longint(PAnsiChar(S)) - Longint(Last)) div SizeOf(AnsiChar)) + 1;
end;
// IMPORTANT NOTE: The StrMatch function does currently not work with the Asterix (*)
function StrMatch(const Substr, S: AnsiString; const Index: Integer): Integer; assembler;
asm
// make sure that strings are not null
TEST EAX, EAX
JZ @@SubstrIsNull
TEST EDX, EDX
JZ @@StrIsNull
// limit index to satisfy 1 <= index, and dec it
DEC ECX
JL @@IndexIsSmall
// EBX will hold the case table, ESI pointer to Str, EDI pointer
// to Substr and EBP # of chars in Substr to compare
PUSH EBX
PUSH ESI
PUSH EDI
PUSH EBP
// set the AnsiString pointers
MOV ESI, EDX
MOV EDI, EAX
// save the Index in EDX
MOV EDX, ECX
// save the address of Str to compute the result
PUSH ESI
// temporary get the length of Substr and Str
MOV EBX, [EDI - AnsiStrRecSize].TAnsiStrRec.Length
MOV ECX, [ESI - AnsiStrRecSize].TAnsiStrRec.Length
// dec the length of Substr because the first char is brought out of it
DEC EBX
JS @@NotFound
// #positions in Str to look at = Length(Str) - Length(Substr) - Index - 2
SUB ECX, EBX
JLE @@NotFound
SUB ECX, EDX
JLE @@NotFound
// # of chars in Substr to compare
MOV EBP, EBX
// point Str to Index'th char
ADD ESI, EDX
// load case map into EBX, and clear EAX & ECX
LEA EBX, AnsiCaseMap
XOR EAX, EAX
XOR ECX, ECX
// bring the first char out of the Substr and point Substr to the next char
MOV CL, [EDI]
INC EDI
// lower case it
MOV CL, [EBX + ECX]
@@FindNext:
// get the current char from Str into al
MOV AL, [ESI]
INC ESI
// check the end of AnsiString
TEST AL, AL
JZ @@NotFound
CMP CL, '*' // Wild Card?
JE @@Compare
CMP CL, '?' // Wild Card?
JE @@Compare
// lower case current char
MOV AL, [EBX + EAX]
// check if the current char matches the primary search char,
// if not continue searching
CMP AL, CL
JNE @@FindNext
@@Compare:
// # of chars in Substr to compare }
MOV EDX, EBP
@@CompareNext:
// dec loop counter and check if we reached the end. If yes then we found it
DEC EDX
JL @@Found
// get the chars from Str and Substr, if they are equal then continue comparing
MOV AL, [EDI + EDX] // char from Substr
CMP AL, '*' // wild card?
JE @@CompareNext
CMP AL, '?' // wild card?
JE @@CompareNext
CMP AL, [ESI + EDX] // equal to PChar(Str)^ ?
JE @@CompareNext
MOV AL, [EBX + EAX + AnsiReOffset] // reverse case?
CMP
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -