2010-12-21 3 views
8

IndexOfIndexOfAnyLastIndexOfLastIndexOfAny find_last_not_ofは、これらの操作を行うように見えるいけない(または多分彼らはありません)。私はstd :: stringのfind_first_not_offind_last_not_ofの等価を探しています。私は拡張クラスを作成することを考えていますが、C#が既にこの機能を提供しているかどうかはわかりません。のC#C++のstd ::文字列find_first_not_ofの同等と

答えて

11
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(); 

それとも、あなたはいくつかの非LINQの拡張メソッドを好む場合。これらは、特にFindLastNotOfのために、わずかに良いパフォーマンスを持っている必要があります、あなたはHashSet<char>charsを変換する場合 - - LINQと非LINQの両方のバージョンで

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; 
} 

を(それはあなたがより良いパフォーマンスを得るかもしれないということが可能ですまたはchar[]配列であっても、ベンチマークを行う必要があります。charsがかなり大きくならない限り、違いは無視しても問題ありません。)

+1

いい仕事ですが、正しい考え方では、ライブラリやAPIルーチンで受け入れられるものはどれですか? MSが失敗したように見えます。 – GTAE86

4

LINQを使用できる場合は、First()Last()メソッドを適切な述語で呼び出すことができます。例えば

、あなたが母音ではありません最初と最後の文字たい場合:

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

をEDIT:上記そのインデックス、文字はないが返されます。そのためには、あなたがSelect()メソッドを使用してインデックスを投影することができ、私たちは何の文字が一致しない場合-1を返却する必要があるので、物事が毛深いなります。また

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; 

、ここに@ abatishchevさんに基づくそれほど複雑ソリューションです答え:

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)); 
+3

正確には 'find_first_not_of'は文字ではなく位置を返します。 – Vlad

+0

@Vlad、あなたが正しいです、それに応じて更新答えます。ありがとう:) –

+3

私はLINQは事をovercomplicatesだと思う。そして、このソリューションは非常に効果がありません。私たちはイテレータと一緒に匿名型の一時オブジェクトのロットを作成しています。ループのための単純な方法を書く方が良いでしょう。 –

0

ここにはRegexソリューションがあります。

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;