简体   繁体   中英

C# equivalent of C++ std::string find_first_not_of and find_last_not_of

IndexOf , IndexOfAny and LastIndexOf , LastIndexOfAny dont seem to do these (or maybe they do). I'm looking for the equialent of std::string's find_first_not_of and find_last_not_of . I'm thinking about creating an extension class but I'm not sure if C# already provides this functionality.

string source = "the quick brown fox jumps over the lazy dog";
string chars = "ogd hte";

int? firstNotOf = source.Select((x, i) => new { Val = x, Idx = (int?)i })
                        .Where(x => chars.IndexOf(x.Val) == -1)
                        .Select(x => x.Idx)
                        .FirstOrDefault();

int? lastNotOf = source.Select((x, i) => new { Val = x, Idx = (int?)i })
                       .Where(x => chars.IndexOf(x.Val) == -1)
                       .Select(x => x.Idx)
                       .LastOrDefault();

Or, if you prefer some non-LINQ extension methods. These should have slightly better performance, especially for FindLastNotOf :

int? firstNotOf = source.FindFirstNotOf(chars);
int? lastNotof = source.FindLastNotOf(chars);

// ...

public static int? FindFirstNotOf(this string source, string chars)
{
    if (source == null) throw new ArgumentNullException("source");
    if (chars == null) throw new ArgumentNullException("chars");
    if (source.Length == 0) return null;
    if (chars.Length == 0) return 0;

    for (int i = 0; i < source.Length; i++)
    {
        if (chars.IndexOf(source[i]) == -1) return i;
    }
    return null;
}

public static int? FindLastNotOf(this string source, string chars)
{
    if (source == null) throw new ArgumentNullException("source");
    if (chars == null) throw new ArgumentNullException("chars");
    if (source.Length == 0) return null;
    if (chars.Length == 0) return source.Length - 1;

    for (int i = source.Length - 1; i >= 0; i--)
    {
        if (chars.IndexOf(source[i]) == -1) return i;
    }
    return null;
}

(It's possible that you might get better performance -- in both the LINQ and non-LINQ versions -- if you convert chars to a HashSet<char> , or maybe even a plain char[] array. You'd need to benchmark to find out, though any difference is likely to be negligible unless chars gets pretty big.)

If the use of LINQ is acceptable, you can call the First() and Last() methods with the appropriate predicate.

For instance, if you want the first and last characters that aren't vowels:

string vowels = "aeiouy";
char first = yourString.First(ch => vowels.IndexOf(ch) < 0);
char last = yourString.Last(ch => vowels.IndexOf(ch) < 0);

EDIT: The above will return the characters, not their indexes. In order to do that, you can project the indexes using the Select() method, but things will get hairy since we need to return -1 if no character matches:

int firstIndex = (yourString.Select(
        (ch, i) => new { Character = ch, Index = i }
    ).First(obj => vowels.IndexOf(obj.Character) < 0)
    ?? new { Character = '\0', Index = -1 }).Index;

int lastIndex = (yourString.Select(
        (ch, i) => new { Character = ch, Index = i }
    ).Last(obj => vowels.IndexOf(obj.Character) < 0)
    ?? new { Character = '\0', Index = -1 }).Index;

Alternatively, here's a less complicated solution based on @abatishchev's answer:

string vowels = "aeiouy";
int firstIndex = yourString.IndexOf(yourString.First(
    ch => vowels.IndexOf(ch) < 0));
int lastIndex = yourString.LastIndexOf(yourString.Last(
    ch => vowels.IndexOf(ch) < 0));

Here's a Regex solution.

string testString = "oueytestie";
var matchFirstNotOf = Regex.Match(testString, @"[^aeiouy]");
int firstNotOf = matchFirstNotOf.Success ? matchFirstNotOf.Index : -1;
var matchLastNotOf = Regex.Match(testString, @"[^aeiouy]", RegexOptions.RightToLeft);
int lastNotOf = matchLastNotOf.Success ? matchLastNotOf.Index : -1;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM