📄 jclstrings.pas
字号:
if S[I] < #32 then
Result := Result + Format('\x%.2x',[Integer(S[I])])
else
Result := Result + S[I];
end;
end;
end;
function StrStripNonNumberChars(const S: AnsiString): AnsiString;
var
I: Integer;
C: AnsiChar;
begin
Result := '';
for I := 1 to Length(S) do
begin
C := S[I];
if CharIsNumberChar(C) then
Result := Result + C;
end;
end;
function StrToHex(const Source: AnsiString): AnsiString;
var
P: PChar;
C, L, N: Integer;
BL, BH: Byte;
S: AnsiString;
begin
Result := '';
if Source <> '' then
begin
S := Source;
L := Length(S);
if Odd(L) then
begin
S := '0' + S;
Inc(L);
end;
P := PChar(S);
SetLength(Result, L div 2);
C := 1;
N := 1;
while C <= L do
begin
BH := CharHex(P^);
Inc(P);
BL := CharHex(P^);
Inc(P);
Inc(C, 2);
if (BH = $FF) or (BL = $FF) then
begin
Result := '';
Exit;
end;
Byte(Result[N]) := Byte((BH shl 4) + BL);
Inc(N);
end;
end;
end;
function StrTrimCharLeft(const S: AnsiString; C: AnsiChar): AnsiString;
var
I, L: Integer;
begin
I := 1;
L := Length(S);
while (I <= L) and (S[I] = C) do Inc(I);
Result := Copy(S, I, L - I + 1);
end;
function StrTrimCharsLeft(const S: AnsiString; const Chars: TSysCharSet): AnsiString;
var
I, L: Integer;
begin
I := 1;
L := Length(S);
while (I <= L) and (S[I] in Chars) do Inc(I);
Result := Copy(S, I, L - I + 1);
end;
function StrTrimCharsRight(const S: AnsiString; const Chars: TSysCharSet): AnsiString;
var
I: Integer;
begin
I := Length(S);
while (I >= 1) and (S[I] in Chars) do Dec(I);
Result := Copy(S, 1, I);
end;
function StrTrimCharRight(const S: AnsiString; C: AnsiChar): AnsiString;
var
I: Integer;
begin
I := Length(S);
while (I >= 1) and (S[I] = C) do Dec(I);
Result := Copy(S, 1, I);
end;
function StrTrimQuotes(const S: AnsiString): AnsiString;
var
First, Last: AnsiChar;
L: Integer;
begin
L := Length(S);
if L > 1 then
begin
First := S[1];
Last := S[L];
if (First = Last) and ((First = AnsiSingleQuote) or (First = AnsiDoubleQuote)) then
Result := Copy(S, 2, L - 2)
else
Result := S;
end
else
Result := S;
end;
function StrUpper(const S: AnsiString): AnsiString;
begin
Result := S;
StrUpperInPlace(Result);
end;
procedure StrUpperInPlace(var S: AnsiString); assembler;
{$IFDEF PIC}
begin
StrCase(S, AnsiUpOffset);
end;
{$ELSE}
asm
// StrCase(Str, AnsiUpOffset)
MOV EDX, AnsiUpOffset
JMP StrCase
end;
{$ENDIF PIC}
procedure StrUpperBuff(S: PAnsiChar); assembler;
{$IFDEF PIC}
begin
StrCaseBuff(S, AnsiUpOffset);
end;
{$ELSE}
asm
// StrCaseBuff(S, UpOffset)
MOV EDX, AnsiUpOffset
JMP StrCaseBuff
end;
{$ENDIF PIC}
{$IFDEF WIN32}
function StrOemToAnsi(const S: AnsiString): AnsiString;
begin
SetLength(Result, Length(S));
OemToAnsiBuff(@S[1], @Result[1], Length(S));
end;
{$ENDIF WIN32}
{$IFDEF WIN32}
function StrAnsiToOem(const S: AnsiString): AnsiString;
begin
SetLength(Result, Length(S));
AnsiToOemBuff(@S[1], @Result[1], Length(S));
end;
{$ENDIF WIN32}
//=== String Management ======================================================
procedure StrAddRef(var S: AnsiString);
var
Foo: AnsiString;
begin
if StrRefCount(S) = -1 then
UniqueString(S)
else
begin
Foo := S;
Pointer(Foo) := nil;
end;
end;
function StrAllocSize(const S: AnsiString): Longint;
var
P: Pointer;
begin
Result := 0;
if Pointer(S) <> nil then
begin
P := Pointer(Integer(Pointer(S)) - AnsiRfOffset);
if Integer(P^) <> -1 then
begin
P := Pointer(Integer(Pointer(S)) - AnsiAlOffset);
Result := Integer(P^);
end;
end;
end;
procedure StrDecRef(var S: AnsiString);
var
Foo: AnsiString;
begin
case StrRefCount(S) of
-1, 0: { nothing } ;
1:
begin
Finalize(S);
Pointer(S) := nil;
end;
else
Pointer(Foo) := Pointer(S);
end;
end;
function StrLen(S: PChar): Integer; assembler;
asm
TEST EAX, EAX
JZ @@EXIT
PUSH EBX
MOV EDX, EAX // save pointer
@L1: MOV EBX, [EAX] // read 4 bytes
ADD EAX, 4 // increment pointer
LEA ECX, [EBX-$01010101] // subtract 1 from each byte
NOT EBX // invert all bytes
AND ECX, EBX // and these two
AND ECX, $80808080 // test all sign bits
JZ @L1 // no zero bytes, continue loop
TEST ECX, $00008080 // test first two bytes
JZ @L2
SHL ECX, 16 // not in the first 2 bytes
SUB EAX, 2
@L2: SHL ECX, 9 // use carry flag to avoid a branch
SBB EAX, EDX // compute length
POP EBX
JZ @@EXIT // Az: SBB sets zero flag
DEC EAX // do not include null terminator
@@EXIT:
end;
function StrLength(const S: AnsiString): Longint;
var
P: Pointer;
begin
Result := 0;
if Pointer(S) <> nil then
begin
P := Pointer(Integer(Pointer(S)) - AnsiLnOffset);
Result := Integer(P^) and (not $80000000 shr 1);
end;
end;
function StrRefCount(const S: AnsiString): Longint;
var
P: Pointer;
begin
Result := 0;
if Pointer(S) <> nil then
begin
P := Pointer(Integer(Pointer(S)) - AnsiRfOffset);
Result := Integer(P^);
end;
end;
procedure StrResetLength(var S: AnsiString);
begin
SetLength(S, StrLen(PChar(S)));
end;
//=== String Search and Replace Routines =====================================
function StrCharCount(const S: AnsiString; C: AnsiChar): Integer;
var
I: Integer;
begin
Result := 0;
for I := 1 to Length(S) do
if S[I] = C then
Inc(Result);
end;
function StrCharsCount(const S: AnsiString; Chars: TSysCharSet): Integer;
var
I: Integer;
begin
Result := 0;
for I := 1 to Length(S) do
if S[I] in Chars then
Inc(Result);
end;
function StrStrCount(const S, SubS: AnsiString): Integer;
var
I: Integer;
begin
Result := 0;
if (Length(SubS) > Length(S)) or (Length(SubS) = 0) or (Length(S) = 0) then
Exit;
if Length(SubS) = 1 then
begin
Result := StrCharCount(S, SubS[1]);
Exit;
end;
I := StrSearch(SubS, S, 1);
if I > 0 then
Inc(Result);
while (I > 0) and (Length(S) > I+Length(SubS)) do
begin
I := StrSearch(SubS, S, I+1);
if I > 0 then
Inc(Result);
end
end;
{$IFDEF PIC}
function _StrCompare(const S1, S2: AnsiString): Integer; forward;
function StrCompare(const S1, S2: AnsiString): Integer;
begin
Result := _StrCompare(S1, S2);
end;
function _StrCompare(const S1, S2: AnsiString): Integer; assembler;
{$ELSE}
function StrCompare(const S1, S2: AnsiString): Integer; assembler;
{$ENDIF PIC}
asm
// check if pointers are equal
CMP EAX, EDX
JE @@Equal
// if S1 is nil return - Length(S2)
TEST EAX, EAX
JZ @@Str1Null
// if S2 is nil return Length(S1)
TEST EDX, EDX
JZ @@Str2Null
// EBX will hold case map, ESI S1, EDI S2
PUSH EBX
PUSH ESI
PUSH EDI
// move AnsiString pointers
MOV ESI, EAX
MOV EDI, EDX
// get the length of strings
MOV EAX, [ESI-AnsiStrRecSize].TAnsiStrRec.Length
MOV EDX, [EDI-AnsiStrRecSize].TAnsiStrRec.Length
// exit if Length(S1) <> Length(S2)
CMP EAX, EDX
JNE @@MissMatch
// check the length just in case
DEC EDX
JS @@InvalidStr
DEC EAX
JS @@InvalidStr
// load case map
LEA EBX, AnsiCaseMap
// make ECX our loop counter
MOV ECX, EAX
// clear working regs
XOR EAX, EAX
XOR EDX, EDX
// get last chars
MOV AL, [ESI+ECX]
MOV DL, [EDI+ECX]
// lower case them
MOV AL, [EBX+EAX]
MOV DL, [EBX+EDX]
// compare them
CMP AL, DL
JNE @@MissMatch
// if there was only 1 char then exit
JECXZ @@Match
@@NextChar:
// case sensitive compare of strings
REPE CMPSB
JE @@Match
// if there was a missmatch try case insensitive compare, get the chars
MOV AL, [ESI-1]
MOV DL, [EDI-1]
// lowercase and compare them, if equal then continue
MOV AL, [EBX+EAX]
MOV DL, [EBX+EDX]
CMP AL, DL
JE @@NextChar
// if we make it here then strings don't match, return the difference
@@MissMatch:
SUB EAX, EDX
POP EDI
POP ESI
POP EBX
RET
@@Match:
// match, return 0
XOR EAX, EAX
POP EDI
POP ESI
POP EBX
RET
@@InvalidStr:
XOR EAX, EAX
DEC EAX
POP EDI
POP ESI
POP EBX
RET
@@Str1Null:
// return = - Length(Str2);
MOV EDX, [EDX-AnsiStrRecSize].TAnsiStrRec.Length
SUB EAX, EDX
RET
@@Str2Null:
// return = Length(Str2);
MOV EAX, [EAX-AnsiStrRecSize].TAnsiStrRec.Length
RET
@@Equal:
XOR EAX, EAX
end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -