1
0
mirror of synced 2024-12-22 09:13:07 +01:00

Added: SkipEmptyItems parameter for Split function

This commit is contained in:
Mark van Renswoude 2014-04-03 14:03:28 +00:00
parent 64eb0b252f
commit 5a7ce7bc99
4 changed files with 69 additions and 46 deletions

View File

@ -25,7 +25,7 @@ package X2Utils;
{$IMAGEBASE $400000}
{$ENDIF IMPLICITBUILDING}
{$DESCRIPTION 'X2Utils'}
{$LIBSUFFIX 'DXE2'}
{$LIBSUFFIX 'XE2'}
{$RUNONLY}
{$IMPLICITBUILD ON}

View File

@ -9,7 +9,7 @@
<ProjectVersion>13.4</ProjectVersion>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Debug</Config>
<Platform Condition="'$(Platform)'==''">Win64</Platform>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>3</TargetedPlatforms>
<AppType>Package</AppType>
</PropertyGroup>
@ -160,7 +160,13 @@
<Source>
<Source Name="MainSource">X2Utils.dpk</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>
<Platforms>
<Platform value="Win64">True</Platform>

View File

@ -9,6 +9,7 @@ type
TStringsTest = class(TTestCase)
published
procedure TestSplit;
procedure TestSkipEmptyItems;
end;
@ -31,6 +32,18 @@ begin
CheckEquals('value2', items[1], 'Items[1]');
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
RegisterTest('Strings', TStringsTest.Suite);

View File

@ -78,7 +78,7 @@ type
* @todo though optimized, it now fails on #0 characters, need
* 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.
*
@ -201,7 +201,7 @@ begin
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
// 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!
@ -253,69 +253,73 @@ const
GrowMax = 256;
var
iCapacity: Integer;
iCount: Integer;
iDelimLen: Integer;
iLength: Integer;
iPos: Integer;
iSize: Integer;
pDelimiter: PChar;
pLast: PChar;
pPos: PChar;
capacity: Integer;
count: Integer;
delimiterLength: Integer;
sourceLength: Integer;
position: Integer;
size: Integer;
delimiter: PChar;
lastPos: PChar;
currentPos: PChar;
begin
// Reserve some space
iCapacity := GrowStart;
iCount := 0;
SetLength(ADest, iCapacity);
capacity := GrowStart;
count := 0;
SetLength(ADest, capacity);
iDelimLen := Length(ADelimiter);
iLength := Length(ASource);
iPos := -1;
pDelimiter := PChar(ADelimiter);
pPos := PChar(ASource);
delimiterLength := Length(ADelimiter);
sourceLength := Length(ASource);
position := 0;
delimiter := PChar(ADelimiter);
currentPos := PChar(ASource);
repeat
// Find delimiter
pLast := pPos;
pPos := StrPosEx(pPos, pDelimiter);
lastPos := currentPos;
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
// Make space
Inc(iCount);
if iCount > iCapacity then
Inc(count);
if count > capacity then
begin
if iCapacity < GrowMax then
Inc(iCapacity, iCapacity)
if capacity < GrowMax then
Inc(capacity, capacity)
else
Inc(iCapacity, GrowMax);
Inc(capacity, GrowMax);
SetLength(ADest, iCapacity);
SetLength(ADest, capacity);
end;
// Copy substring
iSize := (Integer(pPos) - Integer(pLast)) div SizeOf(Char);
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;
SetString(ADest[count - 1], lastPos, size);
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
SetLength(ADest, iCount);
SetLength(ADest, count);
break;
end;