Tuesday, April 5, 2011

How to find the index of the first char in a string that is not in a list.

I know I can loop over the string or build a regex or invert the set (ASCII isn't that big after all) and search for the first instance of that, but Yuck.

What I'm looking for is a nice one liner.

fewer features is better, LINQ is out (for me, don't ask, it's a long story)


The solution I'm going with (unless I see something better)

static int FirstNotMeta(int i, string str)
{
    for(; i < str.Length; i++)
        switch(str[i])
        {
            case '\\':
            case '/':
            case '.':
                continue;
            default:
                return i;
        }
    return -1;
}

OK, I cheated, I know in advance what char's I care about.

From stackoverflow
  • Not all that efficient, but:

    char f(string str, IEnumerable<char> list)
    {
      return str.ToCharArray().First(c => !list.Contains(c))
    }
    
    BCS : Lambdas!! to bad I can't use them. +1 anyway
    Jacksonh : Won't this return the value of the first char, not the index?
  • If you don't have access to LINQ, I think you may just have to write a static method with a loop (which is probably more efficient than LINQ anyway. Remember the compiler will inline small methods when possible.

    The simplest non-LINQ I can come up with is below. I recommend adding braces so scope and the blocks are clear:

    public static char? GetFirstChar(string str, char[] list)
    {
        foreach (char c in str) if (!list.Contains(c)) return c;
        return null;
    }
    

    With C# 3.0 and LINQ:

    char[] list = { 'A', 'B' };
    string str = "AABAGAF";
    
    char first = str.ToArray().Where(c => !list.Contains(c)).FirstOrDefault();
    

    In that case, if there is no non-list character, first will equal 0x0000 (or the character null). You could do this:

    char? first = str.ToArray().Cast<char?>().Where(
        c => !list.Contains(c.Value)).FirstOrDefault();
    

    Then first will be null if there are no matches. This can also be written as:

    var query = from char c in str
                where !list.Contains(c)
                select (char?)c;
    char? first = query.FirstOrDefault();
    
    Mitch Wheat : corrected the syntax of List constructor ...
    Robert Wagner : Thanks Mitch. Should take the time to actually test it :P.
  • This works:

    public static char FindFirstNotAny(this string value, params char[] charset)
    {
        return value.TrimStart(charset)[0];
    }
    
    Mitch Wheat : That's quite nest! (edited to add static keyword)
    Erik Forbes : Very nest indeed, whatever that means. =P
    BCS : "nest": a word describing the condition of having bad aim on key boards and thinking something is cool
    Mitch Wheat : lol, I meant 'neat' but I can't type for toffee!
    Mitch Wheat : @BCS: I should have read all the way to the end of your definition! nice one! i..e very nest
    Robert Wagner : Nice, didn't even think of that. Make sure there IS a character at 0 though.
  • Will this C/C++ example work for you:

    char *strToSearch = "This is the one liner you want"
    char *skipChars = "Tthise";
    size_f numToSkip = strcspn(strToSearch, skipChars);
    

    The strcspn() function scans a string for the complement of the specified set. It returns the number of initial characters that do not include a character in the set.

    Mark Brackett : It'd seem the code behind strcspn would be what's needed...GPL version: http://www.google.com/codesearch?hl=en&q=strcspn()+show:q-MgOPi_2MA:rmZVXVSA8yk:TmTxHZwPCms&sa=N&cd=1&ct=rc&cs_p=ftp://ftp.gnu.org/gnu/gettext/gettext-0.13.tar.gz&cs_f=gettext-0.13/gettext-tools/lib/strcspn.c
    Adam Liss : @Mark: Thanks for the assist!
    BCS : actually, that would do exactly what I need... if it was c# :( Oh well, maybe someone else can use it.

0 comments:

Post a Comment