3

I want to split a string without using the String.Split method.
I found a possible solution here. The code that I use is from the second answer.
This is my code:

public string[] SplitString(string input, char delimiter)
{
    List<String> parts = new List<String>();
    StringBuilder buff = new StringBuilder();

    for (int i = 0; i < input.Length; i++)
    {
        if (input[i] == delimiter)
        {
            parts.Add(buff.ToString());
            buff.Clear();
        }
        else
        {
            buff.Append(input[i]);
        }
    }
    return parts.ToArray();
}

My problem here is that when I try to split a string like this
dog cat car person by " ", the result contains the words without the last one (in this example - person).
If after the last word there is a white space, the result is correct.

I tried to add something like i == input.Length when the for loop is from 0 to i <= input.Length. But the result was still without the last word.
Am I missing something?

Gilad Green
  • 36,708
  • 7
  • 61
  • 95
Sisi
  • 111
  • 2
  • 12
  • 2
    You should check if buffer is not empty at the end of for loop. If it is empty it is done, or there is still a last set of chars left – praty Oct 09 '17 at 10:32
  • 1
    After the loop check the buffer length. If it's more that 0, add it to the list. – Zohar Peled Oct 09 '17 at 10:34

2 Answers2

4

Add another parts.Add(buff.ToString()); after exiting the loop - to flush the last word into the collection. You can check the length before doing so or not as commented and explained why by @hvd.

if(buff.Length != 0)
{
    parts.Add(buff.ToString());
}
return parts.ToArray();

Another approach, instead of using a StringBuilder would be:

public static string[] SplitString(string input, char delimiter)
{
    List<String> parts = new List<String>();
    int start = 0;
    for(int i = 0; i < input.Length; i++)
    {
        if(input[i] == delimiter)
        {
            parts.Add(input.Substring(start, i - start));
            start = i + 1;
        }
    }
    parts.Add(input.Substring(start, input.Length - start));
    return parts.ToArray();
}

Or use yield return and return IEnumerable<string>:

public static IEnumerable<string> SplitString(string input, char delimiter)
{
    int start = 0;
    for(int i = 0; i < input.Length; i++)
    {
        if(input[i] == delimiter)
        {
            yield return input.Substring(start, i - start);
            start = i + 1;
        }
    }
    yield return input.Substring(start, input.Length - start);
}
Gilad Green
  • 36,708
  • 7
  • 61
  • 95
  • 2
    "Before doing so make sure the buffer is not empty" -- No, do not check that. The OP gets empty strings in the results if there are leading spaces or consecutive inner spaces, for consistency the OP should also get empty strings if there are trailing spaces. –  Oct 09 '17 at 10:37
1

Here is what you are missing in your code after for loop:

    for (int i = 0; i < input.Length; i++)
    {
        if (input[i] == delimiter)
        {
            parts.Add(buff.ToString());
            buff.Clear();
        }
        else
        {
            buff.Append(input[i]);
        }
    }

    // This you need to add
    if (!string.IsNullOrEmpty(buff.ToString()))
    {
        parts.Add(buff.ToString());
    }

    return parts.ToArray();
praty
  • 535
  • 2
  • 9