234 lines
5.4 KiB
ObjectPascal
234 lines
5.4 KiB
ObjectPascal
{
|
|
:: X2UtStrings provides various string-related functions.
|
|
::
|
|
:: Last changed: $Date$
|
|
:: Revision: $Rev$
|
|
:: Author: $Author$
|
|
}
|
|
unit X2UtStrings;
|
|
|
|
interface
|
|
type
|
|
TSplitArray = array of String;
|
|
|
|
//:$ Formats the specified size
|
|
//:: If KeepBytes is true, the size will be formatted for decimal separators
|
|
//:: and 'bytes' will be appended. If KeepBytes is false the best suitable
|
|
//:: unit will be chosen (KB, MB, GB).
|
|
function FormatSize(const Bytes: Int64; KeepBytes: Boolean = False): String;
|
|
|
|
//:$ Compares two strings by ordinal value without case sensitivity up to
|
|
//:$ ALength characters.
|
|
function CompareTextL(const AMatch, AAgainst: String;
|
|
const ALength: Integer): Integer;
|
|
|
|
//:$ Compares two strings by ordinal value without case sensitivity up to
|
|
//:$ ALength characters.
|
|
function SameTextL(const AMatch, AAgainst: String;
|
|
const ALength: Integer): Boolean;
|
|
|
|
//:$ Compares AMatch against AAgainst using AAgainst's length.
|
|
function CompareTextS(const AMatch, AAgainst: String): Integer;
|
|
|
|
//:$ Compares AMatch against AAgainst using AAgainst's length.
|
|
function SameTextS(const AMatch, AAgainst: String): Boolean;
|
|
|
|
//:$ Splits a string on the specified delimiter
|
|
procedure Split(const ASource, ADelimiter: String; out ADest: TSplitArray);
|
|
|
|
implementation
|
|
uses
|
|
SysUtils;
|
|
|
|
function FormatSize;
|
|
const
|
|
KB = 1024;
|
|
MB = KB * 1024;
|
|
GB = MB * 1024;
|
|
|
|
var
|
|
dSize: Double;
|
|
sExt: String;
|
|
|
|
begin
|
|
sExt := ' bytes';
|
|
dSize := Bytes;
|
|
|
|
if (not KeepBytes) and (Bytes >= KB) then
|
|
if (Bytes >= KB) and (Bytes < MB) then begin
|
|
// 1 kB ~ 1 MB
|
|
dSize := Bytes / KB;
|
|
sExt := ' KB';
|
|
end else if (Bytes >= MB) and (Bytes < GB) then begin
|
|
// 1 MB ~ 1 GB
|
|
dSize := Bytes / MB;
|
|
sExt := ' MB';
|
|
end else begin
|
|
// 1 GB ~ x
|
|
dSize := Bytes / GB;
|
|
sExt := ' GB';
|
|
end;
|
|
|
|
Result := FormatFloat(',0.##', dSize) + sExt;
|
|
end;
|
|
|
|
function CompareTextL;
|
|
var
|
|
sMatch: String;
|
|
sAgainst: String;
|
|
|
|
begin
|
|
// If there is no reason to copy; don't.
|
|
if Length(AMatch) <= ALength then
|
|
sMatch := AMatch
|
|
else
|
|
sMatch := Copy(AMatch, 1, ALength);
|
|
|
|
if Length(AAgainst) <= ALength then
|
|
sAgainst := AAgainst
|
|
else
|
|
sAgainst := Copy(AAgainst, 1, ALength);
|
|
|
|
Result := CompareText(sMatch, sAgainst);
|
|
end;
|
|
|
|
function SameTextL;
|
|
begin
|
|
Result := (CompareTextL(AMatch, AAgainst, ALength) = 0);
|
|
end;
|
|
|
|
function CompareTextS;
|
|
begin
|
|
Result := CompareTextL(AMatch, AAgainst, Length(AAgainst));
|
|
end;
|
|
|
|
function SameTextS;
|
|
begin
|
|
Result := SameTextL(AMatch, AAgainst, Length(AAgainst));
|
|
end;
|
|
|
|
|
|
procedure Split;
|
|
// StrPos is slow. Sloooooow slow. This function may not be advanced or
|
|
// the fastest one around, but it sure kicks StrPos' ass.
|
|
// 11.5 vs 1.7 seconds on a 2.4 Ghz for 10.000 iterations, baby!
|
|
function StrPosEx(const ASource, ASearch: PChar): PChar;
|
|
var
|
|
pPos: PChar;
|
|
pSub: PChar;
|
|
|
|
begin
|
|
Result := nil;
|
|
|
|
// Search for the first character
|
|
pPos := ASource;
|
|
|
|
while pPos^ <> #0 do
|
|
begin
|
|
if pPos^ = ASearch^ then
|
|
begin
|
|
// Found the first character, match the rest
|
|
pSub := ASearch;
|
|
Result := pPos;
|
|
Inc(pSub);
|
|
Inc(pPos);
|
|
|
|
|
|
while pSub^ <> #0 do
|
|
begin
|
|
if pPos^ <> pSub^ then
|
|
begin
|
|
// No match, resume as normal
|
|
Result := nil;
|
|
break;
|
|
end;
|
|
|
|
Inc(pSub);
|
|
Inc(pPos);
|
|
end;
|
|
|
|
// If still assigned, all characters matched
|
|
if Assigned(Result) then
|
|
exit;
|
|
end else
|
|
Inc(pPos);
|
|
end;
|
|
end;
|
|
|
|
const
|
|
GrowStart = 32;
|
|
GrowMax = 256;
|
|
|
|
var
|
|
iCapacity: Integer;
|
|
iCount: Integer;
|
|
iDelimLen: Integer;
|
|
iLength: Integer;
|
|
iPos: Integer;
|
|
iSize: Integer;
|
|
pDelimiter: PChar;
|
|
pLast: PChar;
|
|
pPos: PChar;
|
|
|
|
begin
|
|
// Reserve some space
|
|
iCapacity := GrowStart;
|
|
iCount := 0;
|
|
SetLength(ADest, iCapacity);
|
|
|
|
iDelimLen := Length(ADelimiter);
|
|
iLength := Length(ASource);
|
|
iPos := -1;
|
|
pDelimiter := PChar(ADelimiter);
|
|
pPos := PChar(ASource);
|
|
|
|
repeat
|
|
// Find delimiter
|
|
pLast := pPos;
|
|
pPos := StrPosEx(pPos, pDelimiter);
|
|
|
|
if pPos <> nil then
|
|
begin
|
|
// Make space
|
|
Inc(iCount);
|
|
if iCount > iCapacity then
|
|
begin
|
|
if iCapacity < GrowMax then
|
|
Inc(iCapacity, iCapacity)
|
|
else
|
|
Inc(iCapacity, GrowMax);
|
|
|
|
SetLength(ADest, iCapacity);
|
|
end;
|
|
|
|
// Copy substring
|
|
iSize := Integer(pPos) - Integer(pLast);
|
|
SetString(ADest[iCount - 1], pLast, iSize);
|
|
|
|
// Move pointer
|
|
Inc(pPos, iDelimLen);
|
|
Inc(iPos, iSize + iDelimLen);
|
|
end else
|
|
begin
|
|
if iPos < iLength then
|
|
begin
|
|
// Copy what's left
|
|
Inc(iCount);
|
|
if iCount > iCapacity then
|
|
SetLength(ADest, iCount);
|
|
|
|
ADest[iCount - 1] := pLast;
|
|
end;
|
|
|
|
if iCount <> iCapacity then
|
|
// Shrink array
|
|
SetLength(ADest, iCount);
|
|
|
|
break;
|
|
end;
|
|
until False;
|
|
end;
|
|
|
|
end.
|
|
|