Added: SkipEmptyItems parameter for Split function
This commit is contained in:
parent
64eb0b252f
commit
5a7ce7bc99
@ -25,7 +25,7 @@ package X2Utils;
|
|||||||
{$IMAGEBASE $400000}
|
{$IMAGEBASE $400000}
|
||||||
{$ENDIF IMPLICITBUILDING}
|
{$ENDIF IMPLICITBUILDING}
|
||||||
{$DESCRIPTION 'X2Utils'}
|
{$DESCRIPTION 'X2Utils'}
|
||||||
{$LIBSUFFIX 'DXE2'}
|
{$LIBSUFFIX 'XE2'}
|
||||||
{$RUNONLY}
|
{$RUNONLY}
|
||||||
{$IMPLICITBUILD ON}
|
{$IMPLICITBUILD ON}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<ProjectVersion>13.4</ProjectVersion>
|
<ProjectVersion>13.4</ProjectVersion>
|
||||||
<Base>True</Base>
|
<Base>True</Base>
|
||||||
<Config Condition="'$(Config)'==''">Debug</Config>
|
<Config Condition="'$(Config)'==''">Debug</Config>
|
||||||
<Platform Condition="'$(Platform)'==''">Win64</Platform>
|
<Platform Condition="'$(Platform)'==''">Win32</Platform>
|
||||||
<TargetedPlatforms>3</TargetedPlatforms>
|
<TargetedPlatforms>3</TargetedPlatforms>
|
||||||
<AppType>Package</AppType>
|
<AppType>Package</AppType>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@ -160,7 +160,13 @@
|
|||||||
<Source>
|
<Source>
|
||||||
<Source Name="MainSource">X2Utils.dpk</Source>
|
<Source Name="MainSource">X2Utils.dpk</Source>
|
||||||
</Source>
|
</Source>
|
||||||
<Excluded_Packages/>
|
<Excluded_Packages>
|
||||||
|
<Excluded_Packages Name="P:\algemeen\bin\DXE2\X2CLGLD.bpl">X²CL GraphicList (Designtime)</Excluded_Packages>
|
||||||
|
<Excluded_Packages Name="P:\algemeen\bin\DXE2\X2CLMBD.bpl">X²CL MenuBar (Designtime)</Excluded_Packages>
|
||||||
|
<Excluded_Packages Name="P:\Algemeen\bin\DXE2\unaDesignDXE2.bpl">UnameIT - Designtime</Excluded_Packages>
|
||||||
|
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k160.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
|
||||||
|
<Excluded_Packages Name="$(BDSBIN)\dclofficexp160.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
|
||||||
|
</Excluded_Packages>
|
||||||
</Delphi.Personality>
|
</Delphi.Personality>
|
||||||
<Platforms>
|
<Platforms>
|
||||||
<Platform value="Win64">True</Platform>
|
<Platform value="Win64">True</Platform>
|
||||||
|
@ -9,6 +9,7 @@ type
|
|||||||
TStringsTest = class(TTestCase)
|
TStringsTest = class(TTestCase)
|
||||||
published
|
published
|
||||||
procedure TestSplit;
|
procedure TestSplit;
|
||||||
|
procedure TestSkipEmptyItems;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -31,6 +32,18 @@ begin
|
|||||||
CheckEquals('value2', items[1], 'Items[1]');
|
CheckEquals('value2', items[1], 'Items[1]');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TStringsTest.TestSkipEmptyItems;
|
||||||
|
var
|
||||||
|
items: TStringDynArray;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Split('/value1///value2//', '/', items, True);
|
||||||
|
CheckEquals(2, Length(items), 'Length');
|
||||||
|
CheckEquals('value1', items[0], 'Items[0]');
|
||||||
|
CheckEquals('value2', items[1], 'Items[1]');
|
||||||
|
end;
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
RegisterTest('Strings', TStringsTest.Suite);
|
RegisterTest('Strings', TStringsTest.Suite);
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ type
|
|||||||
* @todo though optimized, it now fails on #0 characters, need
|
* @todo though optimized, it now fails on #0 characters, need
|
||||||
* to determine the end by checking the AnsiString length.
|
* to determine the end by checking the AnsiString length.
|
||||||
*}
|
*}
|
||||||
procedure Split(const ASource, ADelimiter: String; out ADest: TStringDynArray);
|
procedure Split(const ASource, ADelimiter: String; out ADest: TStringDynArray; ASkipEmptyItems: Boolean = False);
|
||||||
|
|
||||||
{** Appends string parts with a specified glue value.
|
{** Appends string parts with a specified glue value.
|
||||||
*
|
*
|
||||||
@ -201,7 +201,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure Split(const ASource, ADelimiter: String; out ADest: TStringDynArray);
|
procedure Split(const ASource, ADelimiter: String; out ADest: TStringDynArray; ASkipEmptyItems: Boolean);
|
||||||
// StrPos is slow. Sloooooow slow. This function may not be advanced or
|
// StrPos is slow. Sloooooow slow. This function may not be advanced or
|
||||||
// the fastest one around, but it sure kicks StrPos' ass.
|
// 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!
|
// 11.5 vs 1.7 seconds on a 2.4 Ghz for 10.000 iterations, baby!
|
||||||
@ -253,69 +253,73 @@ const
|
|||||||
GrowMax = 256;
|
GrowMax = 256;
|
||||||
|
|
||||||
var
|
var
|
||||||
iCapacity: Integer;
|
capacity: Integer;
|
||||||
iCount: Integer;
|
count: Integer;
|
||||||
iDelimLen: Integer;
|
delimiterLength: Integer;
|
||||||
iLength: Integer;
|
sourceLength: Integer;
|
||||||
iPos: Integer;
|
position: Integer;
|
||||||
iSize: Integer;
|
size: Integer;
|
||||||
pDelimiter: PChar;
|
delimiter: PChar;
|
||||||
pLast: PChar;
|
lastPos: PChar;
|
||||||
pPos: PChar;
|
currentPos: PChar;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
// Reserve some space
|
// Reserve some space
|
||||||
iCapacity := GrowStart;
|
capacity := GrowStart;
|
||||||
iCount := 0;
|
count := 0;
|
||||||
SetLength(ADest, iCapacity);
|
SetLength(ADest, capacity);
|
||||||
|
|
||||||
iDelimLen := Length(ADelimiter);
|
delimiterLength := Length(ADelimiter);
|
||||||
iLength := Length(ASource);
|
sourceLength := Length(ASource);
|
||||||
iPos := -1;
|
position := 0;
|
||||||
pDelimiter := PChar(ADelimiter);
|
delimiter := PChar(ADelimiter);
|
||||||
pPos := PChar(ASource);
|
currentPos := PChar(ASource);
|
||||||
|
|
||||||
repeat
|
repeat
|
||||||
// Find delimiter
|
// Find delimiter
|
||||||
pLast := pPos;
|
lastPos := currentPos;
|
||||||
pPos := StrPosEx(pPos, pDelimiter);
|
currentPos := StrPosEx(currentPos, delimiter);
|
||||||
|
|
||||||
if pPos <> nil then
|
if currentPos <> nil then
|
||||||
|
begin
|
||||||
|
size := (Integer(currentPos) - Integer(lastPos)) div SizeOf(Char);
|
||||||
|
|
||||||
|
if (size > 0) or (not ASkipEmptyItems) then
|
||||||
begin
|
begin
|
||||||
// Make space
|
// Make space
|
||||||
Inc(iCount);
|
Inc(count);
|
||||||
if iCount > iCapacity then
|
if count > capacity then
|
||||||
begin
|
begin
|
||||||
if iCapacity < GrowMax then
|
if capacity < GrowMax then
|
||||||
Inc(iCapacity, iCapacity)
|
Inc(capacity, capacity)
|
||||||
else
|
else
|
||||||
Inc(iCapacity, GrowMax);
|
Inc(capacity, GrowMax);
|
||||||
|
|
||||||
SetLength(ADest, iCapacity);
|
SetLength(ADest, capacity);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Copy substring
|
// Copy substring
|
||||||
iSize := (Integer(pPos) - Integer(pLast)) div SizeOf(Char);
|
SetString(ADest[count - 1], lastPos, size);
|
||||||
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;
|
end;
|
||||||
|
|
||||||
if iCount <> iCapacity then
|
// Move pointer
|
||||||
|
Inc(currentPos, delimiterLength);
|
||||||
|
Inc(position, size + delimiterLength);
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
if position < sourceLength then
|
||||||
|
begin
|
||||||
|
// Copy what's left
|
||||||
|
Inc(count);
|
||||||
|
if count > capacity then
|
||||||
|
SetLength(ADest, count);
|
||||||
|
|
||||||
|
ADest[count - 1] := lastPos;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if count <> capacity then
|
||||||
// Shrink array
|
// Shrink array
|
||||||
SetLength(ADest, iCount);
|
SetLength(ADest, count);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
end;
|
end;
|
||||||
|
Loading…
Reference in New Issue
Block a user