📄 jclstrings.pas
字号:
Result := Result + AnsiVerticalTab;
'\':
Result := Result + '\';
'"':
Result := Result + '"';
'''':
Result := Result + ''''; // Optionally escaped
'?':
Result := Result + '?'; // Optionally escaped
'x':
if I < Len then
// Start of hex escape sequence
HandleHexEscapeSeq
else
// '\x' at end of AnsiString is not escape sequence
Result := Result + '\x';
'0'..'7':
// start of octal escape sequence
HandleOctEscapeSeq;
else
// no escape sequence
Result := Result + '\' + S[I];
end;
end;
Inc(I);
end;
end;
function StrLower(const S: AnsiString): AnsiString;
begin
Result := S;
StrLowerInPlace(Result);
end;
procedure StrLowerInPlace(var S: AnsiString); assembler;
{$IFDEF PIC}
begin
StrCase(S, AnsiLoOffset);
end;
{$ELSE}
asm
// StrCase(S, AnsiLoOffset)
XOR EDX, EDX // MOV EDX, LoOffset
JMP StrCase
end;
{$ENDIF PIC}
procedure StrLowerBuff(S: PAnsiChar); assembler;
{$IFDEF PIC}
begin
StrCaseBuff(S, AnsiLoOffset);
end;
{$ELSE}
asm
// StrCaseBuff(S, LoOffset)
XOR EDX, EDX // MOV EDX, LoOffset
JMP StrCaseBuff
end;
{$ENDIF PIC}
procedure StrMove(var Dest: AnsiString; const Source: AnsiString;
const ToIndex, FromIndex, Count: Integer);
begin
// Check strings
if (Source = '') or (Length(Dest) = 0) then
Exit;
// Check FromIndex
if (FromIndex <= 0) or (FromIndex > Length(Source)) or
(ToIndex <= 0) or (ToIndex > Length(Dest)) or
((FromIndex + Count - 1) > Length(Source)) or ((ToIndex + Count - 1) > Length(Dest)) then
{ TODO : Is failure without notice the proper thing to do here? }
Exit;
// Move
Move(Source[FromIndex], Dest[ToIndex], Count);
end;
function StrPadLeft(const S: AnsiString; Len: Integer; C: AnsiChar): AnsiString;
var
L: Integer;
begin
L := Length(S);
if L < Len then
Result := StringOfChar(C, Len - L) + S
else
Result := S;
end;
function StrPadRight(const S: AnsiString; Len: Integer; C: AnsiChar): AnsiString;
var
L: Integer;
begin
L := Length(S);
if L < Len then
Result := S + StringOfChar(C, Len - L)
else
Result := S;
end;
function StrProper(const S: AnsiString): AnsiString;
begin
Result := S;
StrProperBuff(PChar(Result));
end;
procedure StrProperBuff(S: PAnsiChar);
begin
if (S <> nil) and (S^ <> #0) then
begin
StrLowerBuff(S);
S^ := CharUpper(S^);
end;
end;
function StrQuote(const S: AnsiString; C: AnsiChar): AnsiString;
var
L: Integer;
begin
L := Length(S);
Result := S;
if L > 0 then
begin
if Result[1] <> C then
begin
Result := C + Result;
Inc(L);
end;
if Result[L] <> C then
Result := Result + C;
end;
end;
function StrRemoveChars(const S: AnsiString; const Chars: TSysCharSet): AnsiString;
var
Source, Dest: PChar;
begin
SetLength(Result, Length(S));
UniqueString(Result);
Source := PChar(S);
Dest := PChar(Result);
while (Source <> nil) and (Source^ <> #0) do
begin
if not (Source^ in Chars) then
begin
Dest^ := Source^;
Inc(Dest);
end;
Inc(Source);
end;
SetLength(Result, (Longint(Dest) - Longint(PChar(Result))) div SizeOf(AnsiChar));
end;
function StrKeepChars(const S: AnsiString; const Chars: TSysCharSet): AnsiString;
var
Source, Dest: PChar;
begin
SetLength(Result, Length(S));
UniqueString(Result);
Source := PChar(S);
Dest := PChar(Result);
while (Source <> nil) and (Source^ <> #0) do
begin
if Source^ in Chars then
begin
Dest^ := Source^;
Inc(Dest);
end;
Inc(Source);
end;
SetLength(Result, (Longint(Dest) - Longint(PChar(Result))) div SizeOf(AnsiChar));
end;
function StrRepeat(const S: AnsiString; Count: Integer): AnsiString;
var
L: Integer;
P: PChar;
begin
L := Length(S);
SetLength(Result, Count * L);
P := Pointer(Result);
while Count > 0 do
begin
Move(Pointer(S)^, P^, L);
P := P + L;
Dec(Count);
end;
end;
function StrRepeatLength(const S: AnsiString; Const L: Integer): AnsiString;
var
Count: Integer;
LenS: Integer;
P: PChar;
begin
Result := '';
LenS := Length(S);
if LenS > 0 then
begin
Count := L div LenS;
if Count * LenS < L then
Inc(Count);
SetLength(Result, Count * LenS);
P := Pointer(Result);
while Count> 0 do
begin
Move(Pointer(S)^, P^, LenS);
P := P + LenS;
Dec(Count);
end;
if Length(S) > L then
SetLength(Result, L);
end;
end;
procedure StrReplace(var S: AnsiString; const Search, Replace: AnsiString; Flags: TReplaceFlags);
var
SearchStr: AnsiString;
ResultStr: AnsiString; { result string }
SourcePtr: PChar; { pointer into S of character under examination }
SourceMatchPtr: PChar; { pointers into S and Search when first character has }
SearchMatchPtr: PChar; { been matched and we're probing for a complete match }
ResultPtr: PChar; { pointer into Result of character being written }
ResultIndex,
SearchLength, { length of search string }
ReplaceLength, { length of replace string }
BufferLength, { length of temporary result buffer }
ResultLength: Integer; { length of result string }
C: Char; { first character of search string }
IgnoreCase: Boolean;
begin
if Search = '' then
if S = '' then
begin
S := Replace;
Exit;
end
else
raise EJclStringError.CreateRes(@RsBlankSearchString);
if S <> '' then
begin
IgnoreCase := rfIgnoreCase in Flags;
if IgnoreCase then
SearchStr := AnsiUpperCase(Search)
else
SearchStr := Search;
{ avoid having to call Length() within the loop }
SearchLength := Length(Search);
ReplaceLength := Length(Replace);
ResultLength := Length(S);
BufferLength := ResultLength;
SetLength(ResultStr, BufferLength);
{ get pointers to begin of source and result }
ResultPtr := PChar(ResultStr);
SourcePtr := PChar(S);
C := SearchStr[1];
{ while we haven't reached the end of the string }
while True do
begin
{ copy characters until we find the first character of the search string }
if IgnoreCase then
while (CharUpper(SourcePtr^) <> C) and (SourcePtr^ <> #0) do
begin
ResultPtr^ := SourcePtr^;
Inc(ResultPtr);
Inc(SourcePtr);
end
else
while (SourcePtr^ <> C) and (SourcePtr^ <> #0) do
begin
ResultPtr^ := SourcePtr^;
Inc(ResultPtr);
Inc(SourcePtr);
end;
{ did we find that first character or did we hit the end of the string? }
if SourcePtr^ = #0 then
Break
else
begin
{ continue comparing, +1 because first character was matched already }
SourceMatchPtr := SourcePtr + 1;
SearchMatchPtr := PChar(SearchStr) + 1;
if IgnoreCase then
while (CharUpper(SourceMatchPtr^) = SearchMatchPtr^) and (SearchMatchPtr^ <> #0) do
begin
Inc(SourceMatchPtr);
Inc(SearchMatchPtr);
end
else
while (SourceMatchPtr^ = SearchMatchPtr^) and (SearchMatchPtr^ <> #0) do
begin
Inc(SourceMatchPtr);
Inc(SearchMatchPtr);
end;
{ did we find a complete match? }
if SearchMatchPtr^ = #0 then
begin
// keep track of result length
Inc(ResultLength, ReplaceLength - SearchLength);
if ReplaceLength > 0 then
begin
// increase buffer size if required
if ResultLength > BufferLength then
begin
BufferLength := ResultLength * 2;
ResultIndex := ResultPtr - PChar(ResultStr) + 1;
SetLength(ResultStr, BufferLength);
ResultPtr := @ResultStr[ResultIndex];
end;
{ append replace to result and move past the search string in source }
Move((@Replace[1])^, ResultPtr^, ReplaceLength);
end;
Inc(SourcePtr, SearchLength);
Inc(ResultPtr, ReplaceLength);
{ replace all instances or just one? }
if not (rfReplaceAll in Flags) then
begin
{ just one, copy until end of source and break out of loop }
while SourcePtr^ <> #0 do
begin
ResultPtr^ := SourcePtr^;
Inc(ResultPtr);
Inc(SourcePtr);
end;
Break;
end;
end
else
begin
{ copy current character and start over with the next }
ResultPtr^ := SourcePtr^;
Inc(ResultPtr);
Inc(SourcePtr);
end;
end;
end;
{ set result length and copy result into S }
SetLength(ResultStr, ResultLength);
S := ResultStr;
end;
end;
function StrReplaceChar(const S: AnsiString; const Source, Replace: Char): AnsiString;
var
I: Integer;
begin
Result := S;
for I := 1 to Length(S) do
if Result[I] = Source then
Result[I] := Replace;
end;
function StrReplaceChars(const S: AnsiString; const Chars: TSysCharSet; Replace: Char): AnsiString;
var
I: Integer;
begin
Result := S;
for I := 1 to Length(S) do
if Result[I] in Chars then
Result[I] := Replace;
end;
function StrReplaceButChars(const S: AnsiString; const Chars: TSysCharSet;
Replace: Char): AnsiString;
var
I: Integer;
begin
Result := S;
for I := 1 to Length(S) do
if not (Result[I] in Chars) then
Result[I] := Replace;
end;
function StrReverse(const S: AnsiString): AnsiString;
begin
Result := S;
StrReverseInplace(Result);
end;
procedure StrReverseInPlace(var S: AnsiString);
var
P1, P2: PChar;
C: AnsiChar;
begin
UniqueString(S);
P1 := PChar(S);
P2 := P1 + SizeOf(AnsiChar) * (Length(S) - 1);
while P1 < P2 do
begin
C := P1^;
P1^ := P2^;
P2^ := C;
Inc(P1);
Dec(P2);
end;
end;
function StrSingleQuote(const S: AnsiString): AnsiString;
begin
Result := AnsiSingleQuote + S + AnsiSingleQuote;
end;
function StrSmartCase(const S: AnsiString; Delimiters: TSysCharSet): AnsiString;
var
Source, Dest: PChar;
begin
Result := '';
if Delimiters = [] then
Include(Delimiters, AnsiSpace);
if S <> '' then
begin
Result := S;
UniqueString(Result);
Source := PChar(S);
Dest := PChar(Result);
Inc(Dest);
while Source^ <> #0 do
begin
if (Source^ in Delimiters) and (Dest^ <> #0) then
Dest^ := CharUpper(Dest^);
Inc(Dest);
Inc(Source);
end;
Result[1] := CharUpper(Result[1]);
end;
end;
function StrStringToEscaped(const S: AnsiString): AnsiString;
var
I: Integer;
begin
Result := '';
for I := 1 to Length(S) do
begin
case S[I] of
AnsiBackspace:
Result := Result + '\b';
AnsiBell:
Result := Result + '\a';
AnsiCarriageReturn:
Result := Result + '\r';
AnsiFormFeed:
Result := Result + '\f';
AnsiLineFeed:
Result := Result + '\n';
AnsiTab:
Result := Result + '\t';
AnsiVerticalTab:
Result := Result + '\v';
'\':
Result := Result + '\\';
'"':
Result := Result + '\"';
else
// Characters < ' ' are escaped with hex sequence
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -