1

Is there a way to exclude blank strings from the dynamic array resulting of the SplitString function (Delphi XE, StrUtils), without having to iterate through the array?

If not, can anyone suggest the most efficient way to do it? Right now I'm doing it like this:

function SplitStringNoEmpty(myString : string; myDelimiters : string):TStringDynArray;
var
    words_array_pre : TStringDynArray;
    words_array_pos : TStringDynArray;
    array_length : Integer;
    actual_length : Integer;
    current_word : string;

    procedure AddElement(const Str: string);
    begin
      words_array_pos[actual_length]:= Str;
      inc(actual_length);
    end;
begin
    words_array_pre:= SplitString(myString, whitespaceNewLineCharacterSet + punctuationCharacterSet);
    array_length:= Length(words_array_pre);
    if (array_length >0) then
    begin
      actual_length:= 0;
      SetLength(words_array_pos, array_length);
      for current_word in words_array_pre do
      begin
        if (current_word <> '') then
          AddElement(current_word);
      end;
      SetLength(words_array_pos, actual_length);
      result:= words_array_pos;
    end
    else
      result:= words_array_pre;
end;
1
  • Have you considered just doing whatever SplitString does, but without including empty elements in the result? Commented Apr 2, 2012 at 20:16

2 Answers 2

3

You can write your own implementation of the SplitString function ignoring the empty strings.

Check this sample

function SplitString2(const S, Delimiters: string): TStringDynArray;
var
  LIndex, SIndex, FIndex, LMax, LPos: Integer;
  foo : string;
begin
  Result := nil;

  if S <> '' then
  begin
    LPos   := 0;
    LMax   := 0;
    SIndex := 1;

    for LIndex := 1 to Length(S) do
      if IsDelimiter(Delimiters, S, LIndex) then Inc(LMax);

    SetLength(Result, LMax + 1);

    repeat
      FIndex := FindDelimiter(Delimiters, S, SIndex);
      if FIndex <> 0 then
      begin
        foo:= Copy(S, SIndex, FIndex - SIndex);
        if foo<>'' then
        begin
          Result[LPos] := foo;
          Inc(LPos);
        end;
        SIndex := FIndex + 1;
      end;
    until (LPos = LMax) or (FIndex=0);

    if LPos<LMax then
     SetLength(Result, LPos + 1);

    foo:=Copy(S, SIndex, Length(S) - SIndex + 1);
    if foo<>'' then
     Result[LMax] := foo
    else
     SetLength(Result, LPos);
  end;
end;
Sign up to request clarification or add additional context in comments.

Comments

2

It's impossible to remove certain elements of an array without iterating over the array — how else would you know which elements to remove? The improvements to make to your code are to remove the need to allocate an extra array. You can cull the original array in-place:

function SplitStringNoEmpty(const s, delimiters: string): TStringDynArray;
var
  Src, Dest: Integer;
begin
  Result := SplitString(s, delimiters);
  if Length(Result) <> 0 then begin
    // Push all non-empty values to front of array
    Dest := 0;
    for Src := 0 to High(Result) do
      if Result[Src] <> '' then begin
        if Src <> Dest then
          Result[Dest] := Result[Src];
        Inc(Dest);
      end;
    // Remove excess from end of array
    SetLength(Result, Dest);
  end;
end;

1 Comment

Thanks for the optimization Rob! StrUtils should be added a similar function.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.