6
\$\begingroup\$

I have some underscore-delimited strings like abc_def_ghi. I would like to get a substring out of the string made of one or more delimited substrings, so that if I call:

getUnderscoreSubstring("abc_def_ghi",2)

then I get:

abc_def

This is the C# code I'm using:

public string getUnderscoreSubstring(string fullStr,int substringCount)
{
    string[] splitArray = fullStr.Split('_');
    if (substringCount>splitArray.Count())
    {
        return null;
    }
    else
    {
        string output = "";
        for(int c=0;c<substringCount;c++)
        {
            output += splitArray[c];
            if (c<substringCount-1)
            {
                output += "_";
            }
        }
        return output;
    }
}

I'm wondering if there's a simpler way to rewrite this, possibly using extension methods.

\$\endgroup\$
2
  • \$\begingroup\$ Please clarify your motivation. What do you want to be the result of getUnderscoreSubstring("__abc_def_ghi", 2), and why? \$\endgroup\$ Apr 30 '15 at 23:52
  • \$\begingroup\$ I don't have any values like that in the data set; they would be excluded from these function calls by prior validation. \$\endgroup\$
    – sigil
    Apr 30 '15 at 23:57
8
\$\begingroup\$

Yes, you can definitely simplify this.

public string GetSubstring(string input, int count, char delimiter)
{
    return string.Join(delimiter.ToString(), 
                       input.Split(delimiter).Take(count));
}

Calling it is as easy as GetSubstring(input, 2, '_')

What does it do?

  • Split the input string by the delimiter
  • Take the amount of substrings you want
  • Glue the selected substrings together with your delimiter

Very short and sexy!

This doesn't take the substringCount > splitArray.Count() in account but you can easily add that yourself: just split up the oneliner and add the appropriate check.


Now, some comments about your code:

  • Use .Length instead of .Count() when possible: the former will always be an O(1) operation, the latter sometimes an O(n). It won't make a difference here since an array implements ICollection<T> (and will use this optimization) but it's a good practice to observe.
  • Returning null is typically avoided for good reasons, consider an empty string or exception instead (don't go for the exception in this case).
  • I prefer to explicitly use string.Empty rather than an empty string to avoid confusion.
  • Write your variable names in full -- nobody is helped by abbreviating them.
  • Use a StringBuilder to concatenate in a loop to avoid unnecessary string object creating.
  • Leave some space in your code, it will read more fluently.
\$\endgroup\$
2
\$\begingroup\$

Basically, you want to find the substringCountth occurrence of '_' in the string, and return all the characters before that.

Basing on the code from https://stackoverflow.com/a/11363213/1108056

private int IndexOfNth(string str, char c, int n)
{
    int index = -1;
    while (n-- > 0)
    {
        index = str.IndexOf(c, index + 1);
        if (index == -1) break;
    }
    return index;
}

public string GetSubstring(string input, int count, char delimiter)
{
    return input.Substring(0,IndexOfNth(input, delimiter, count));
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.