1
0
mirror of synced 2024-12-22 17:23: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} {$IMAGEBASE $400000}
{$ENDIF IMPLICITBUILDING} {$ENDIF IMPLICITBUILDING}
{$DESCRIPTION 'X2Utils'} {$DESCRIPTION 'X2Utils'}
{$LIBSUFFIX 'DXE2'} {$LIBSUFFIX 'XE2'}
{$RUNONLY} {$RUNONLY}
{$IMPLICITBUILD ON} {$IMPLICITBUILD ON}

View File

@ -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>

View File

@ -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);

View File

@ -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 begin
// Make space size := (Integer(currentPos) - Integer(lastPos)) div SizeOf(Char);
Inc(iCount);
if iCount > iCapacity then if (size > 0) or (not ASkipEmptyItems) then
begin begin
if iCapacity < GrowMax then // Make space
Inc(iCapacity, iCapacity) Inc(count);
else if count > capacity then
Inc(iCapacity, GrowMax); begin
if capacity < GrowMax then
Inc(capacity, capacity)
else
Inc(capacity, GrowMax);
SetLength(ADest, iCapacity); SetLength(ADest, capacity);
end;
// Copy substring
SetString(ADest[count - 1], lastPos, size);
end; end;
// Copy substring
iSize := (Integer(pPos) - Integer(pLast)) div SizeOf(Char);
SetString(ADest[iCount - 1], pLast, iSize);
// Move pointer // Move pointer
Inc(pPos, iDelimLen); Inc(currentPos, delimiterLength);
Inc(iPos, iSize + iDelimLen); Inc(position, size + delimiterLength);
end else end else
begin begin
if iPos < iLength then if position < sourceLength then
begin begin
// Copy what's left // Copy what's left
Inc(iCount); Inc(count);
if iCount > iCapacity then if count > capacity then
SetLength(ADest, iCount); SetLength(ADest, count);
ADest[iCount - 1] := pLast; ADest[count - 1] := lastPos;
end; end;
if iCount <> iCapacity then if count <> capacity then
// Shrink array // Shrink array
SetLength(ADest, iCount); SetLength(ADest, count);
break; break;
end; end;