diff --git a/Packages/DXE2/X2Utils.dpk b/Packages/DXE2/X2Utils.dpk index e3806f5..a9731ab 100644 --- a/Packages/DXE2/X2Utils.dpk +++ b/Packages/DXE2/X2Utils.dpk @@ -25,7 +25,7 @@ package X2Utils; {$IMAGEBASE $400000} {$ENDIF IMPLICITBUILDING} {$DESCRIPTION 'X2Utils'} -{$LIBSUFFIX 'DXE2'} +{$LIBSUFFIX 'XE2'} {$RUNONLY} {$IMPLICITBUILD ON} diff --git a/Packages/DXE2/X2Utils.dproj b/Packages/DXE2/X2Utils.dproj index 9d6898f..78af53b 100644 --- a/Packages/DXE2/X2Utils.dproj +++ b/Packages/DXE2/X2Utils.dproj @@ -9,7 +9,7 @@ 13.4 True Debug - Win64 + Win32 3 Package @@ -160,7 +160,13 @@ X2Utils.dpk - + + X²CL GraphicList (Designtime) + X²CL MenuBar (Designtime) + UnameIT - Designtime + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + True diff --git a/UnitTests/Units/StringsTest.pas b/UnitTests/Units/StringsTest.pas index cef60dd..503530d 100644 --- a/UnitTests/Units/StringsTest.pas +++ b/UnitTests/Units/StringsTest.pas @@ -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); diff --git a/X2UtStrings.pas b/X2UtStrings.pas index 6c7f5fb..bc2f8c9 100644 --- a/X2UtStrings.pas +++ b/X2UtStrings.pas @@ -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 - // Make space - Inc(iCount); - if iCount > iCapacity then + size := (Integer(currentPos) - Integer(lastPos)) div SizeOf(Char); + + if (size > 0) or (not ASkipEmptyItems) then begin - if iCapacity < GrowMax then - Inc(iCapacity, iCapacity) - else - Inc(iCapacity, GrowMax); + // Make space + Inc(count); + if count > capacity then + 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; - // 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); + Inc(currentPos, delimiterLength); + Inc(position, size + delimiterLength); end else begin - if iPos < iLength then + if position < sourceLength then begin // Copy what's left - Inc(iCount); - if iCount > iCapacity then - SetLength(ADest, iCount); + Inc(count); + if count > capacity then + SetLength(ADest, count); - ADest[iCount - 1] := pLast; + ADest[count - 1] := lastPos; end; - if iCount <> iCapacity then + if count <> capacity then // Shrink array - SetLength(ADest, iCount); + SetLength(ADest, count); break; end;