views:

69

answers:

4

Here is another old function I have from my C# 1 days, what would be a more elegant way to write it:

//method: gets the text in a string in front of a marker, if marker is not there, then return empty string
//example: GetTextAfterMarker("documents/jan/letter043.doc","/") returns "documents"
//example: GetTextAfterMarker("letter043.doc","/") returns ""
//rank:8
public static string GetTextAfterMarker(string line, string marker)  {
    string r = "";

    int pos = line.IndexOf(marker);
    if(pos != -1) {
        r = line.Substring(pos+(marker.Length),line.Length-pos-(marker.Length));
    } else {
        r = "";
    }

    return r;
}
A: 

You could use regular expressions:

    public static string GetTextBeforeMarker(string line, string marker)
    {
        if (String.IsNullOrEmpty(line))
            throw new ArgumentException("line is null or empty.", "line");
        if (String.IsNullOrEmpty(marker))
            throw new ArgumentException("marker is null or empty.", "marker");
        string EscapedMarker = Regex.Escape(marker);
        return Regex.Match(line, "([^" + EscapedMarker + "]+)" + EscapedMarker).Groups[1].Value;
    }
Robert Venables
It fails on the second example in the code comments in the question
Fredrik Mörk
Thanks - Updated.
Robert Venables
+1  A: 

I find the name somewhat strange, given that it should return the text appearing before the first marker. But this one does the same job, I think (I took the liberty to change the name):

public static string GetTextBeforeMarker(string line, string marker)
{
    if (line == null)
    {
        throw new ArgumentNullException("line");
    }

    if (marker == null)
    {
        throw new ArgumentNullException("marker");
    }

    string result = line.Split(new string[] { marker }, StringSplitOptions.None)[0];
    return line.Equals(result) ? string.Empty : result;
}

Explanation: split the string into an array using the marker as split argument. If the first element of the result is the same as the input, the marker was not in the string, so we return an empty string, otherwise we return the first element (which is the text up to the first occurrence of the marker).

Fredrik Mörk
That's a nice use of Split(), I used to create GetTextAfterMarker here, but it could use some refactoring since I didn't know how to refer to Count() inside the brackets: http://stackoverflow.com/questions/1172216/how-can-i-refactor-this-c-code-using-split
Edward Tanguay
+1  A: 

Am I missing something? Wouldn't this be more simple? Also I prefer Substring to Split.

public static string GetTextAfterMarker(string line, string marker)  {
    int pos = line.IndexOf(marker);
    if (pos == -1)
       return string.Empty;
    return line.Substring(0,pos);
}
bruno conde
This looks like the best one to me. I can't imagine Split being more efficient than IndexOf followed by Substring. And if you want to get really terse: return ((pos = line.IndexOf(marker) == -1) ? string.Empty : line.Substring(0, pos);
Jim Mischel
I ran some tests on the two solutions (ran 100000 iterations of each, measuring time with Stopwatch), and found - somewhat to my surprise - that the Split-approach rather consistently worked approximately twice as fast as the IndexOf/Substring approach (and that includes the null-checks in my method). The Split approach also seem to keep its speed when given strings without the marker, a scenario that seemed to slow down the IndexOf/Substring solution.
Fredrik Mörk
..and those results *really* sparked my curiosity (I found them strange), so I went to optimize both methods. If bruno's call to IndexOf is changed to `line.IndexOf(marker,0,line.Length, StringComparison.Ordinal)` it becomes significantly faster, and then the IndexOf/Substring solution wins :o)
Fredrik Mörk
wow... thanks for the contribution :) I'll inspect line.IndexOf(marker,0,line.Length, StringComparison.Ordinal)
bruno conde
A brief look at the IL for String.Split() (actually, an internal method called InternalSplitKeepEmptyENtries) indicates that String.Split() uses ordinal string comparisons. Interesting.
Jim Mischel
A: 
public static string GetTextBeforeMarker(string line, string marker)  {
    return GetTextAfterMarker(string line, string marker);
}
DrG