文字列にいくつかの文字列が含まれているかどうかを確認する方法


97

C#で、文字列sに「a」、「b」、または「c」が含まれているかどうかを確認したいと思います。使用するよりも良い解決策を探しています

if (s.contains("a")||s.contains("b")||s.contains("c"))

1
複雑なケースでは、trieデータ構造を調べます。
悲惨な変数

回答:



94

まあ、これはいつもあります:

public static bool ContainsAny(this string haystack, params string[] needles)
{
    foreach (string needle in needles)
    {
        if (haystack.Contains(needle))
            return true;
    }

    return false;
}

使用法:

bool anyLuck = s.ContainsAny("a", "b", "c");

||ただし、比較のチェーンのパフォーマンスに匹敵するものはありません。


12
この素晴らしいソリューションに新しい短い構文を追加する public static bool ContainsAny(this string haystack, params string[] needles) { return needles.Any(haystack.Contains); }
simonkaspers1

シンプルで明白なソリューション。しかし、haystack文字列による複数の反復を必要としないすぐに使用できる実装はありますか?私はそれを自分で実装し、ヘイスタック文字列の文字を繰り返し処理して、針の最初の文字を一度に順番に比較することができますが、そのような簡単な解決策がいくつかの有名なNuGetライブラリにまだ実装されていないことは信じられません。
RollerKostr

@RollerKostr C#には(まだ)組み込まれていないので、このような単純なソリューションのためにプロジェクトに依存関係を追加するのはなぜですか?
jmdon 2018

70

以下は、実質的に同じですがよりスケーラブルなLINQソリューションです。

new[] { "a", "b", "c" }.Any(c => s.Contains(c))

3
これは、パフォーマンスの意味ではなく、文字を追加するのが簡単であるという意味でスケーラブルです... :)
Guffa

2
もちろんそうです。おそらく、「より拡張性の高い」単語の方が適切な選択でした。
ジェフメルカド2010

パフォーマンスはひどくありません。とにかく、解釈された正規表現よりも優れています。
Steven Sudit、2010

完全を期すための素晴らしい答えは、最初に入力文字列を配列に分割できます。例:var splitStringArray = someString.Split( ''); その後、次のようなことができます。
Tahir Khalid、

45
var values = new [] {"abc", "def", "ghj"};
var str = "abcedasdkljre";
values.Any(str.Contains);

21

正規表現で試すことができます

string s;
Regex r = new Regex ("a|b|c");
bool containsAny = r.IsMatch (s);

1
+1。ただし、彼は単一の文字を探しているため、linqソリューションまたはindexOfAnyの方が効率的かもしれません。
Joel Coehoorn、2010

正規表現の場合は+1。それが、IndexOfAnyがなかったら、私が行ったことだろう
Stavros

1
正規表現はこれには過剰です。
Steven Sudit、2010

3
正規表現がこれに対して過剰であると人々が言うのはなぜですか?正規表現が1回コンパイルされて複数回使用され、文字列にcのみが含まれている場合、またはcが先頭近くにあり、a、bが末尾近くにある場合、正規表現の方がはるかに効率的です。
Bruceboughton 2010

-、「」などの特殊文字では機能しません
。`

14

特定のStringComparison(たとえば、大文字と小文字を区別しない)を含むContainsAnyが必要な場合は、このString Extentionsメソッドを使用できます。

public static class StringExtensions
{
    public static bool ContainsAny(this string input, IEnumerable<string> containsKeywords, StringComparison comparisonType)
    {
        return containsKeywords.Any(keyword => input.IndexOf(keyword, comparisonType) >= 0);
    }
}

での使用StringComparison.CurrentCultureIgnoreCase

var input = "My STRING contains Many Substrings";
var substrings = new[] {"string", "many substrings", "not containing this string" };
input.ContainsAny(substrings, StringComparison.CurrentCultureIgnoreCase);
// The statement above returns true.

xyz”.ContainsAny(substrings, StringComparison.CurrentCultureIgnoreCase);
// This statement returns false.

2
この回答を改善するための1つのメモ。paramsキーワードを使用して、よりエレガントに記述できます:ContainsAny(この文字列入力、StringComparison比較タイプ、params文字列[] containsKeywords)、input.ContainsAny(substrings、StringComparison.CurrentCultureIgnoreCase、 "string"、 "many substrings" ...のように使用できます。 etc)
ローマボロドフ2017年

7

これは「より優れたソリューション」であり、非常に簡単です

if(new string[] { "A", "B", ... }.Any(s=>myString.Contains(s)))

4

文字列は文字のコレクションなので、それらに対してLINQ拡張メソッドを使用できます。

if (s.Any(c => c == 'a' || c == 'b' || c == 'c')) ...

これは文字列を1回スキャンして、一致が見つかるまで文字ごとに文字列を1回スキャンするのではなく、最初の出現で停止します。

これは、たとえば文字の範囲をチェックするなど、好きな式に使用することもできます。

if (s.Any(c => c >= 'a' && c <= 'c')) ...

同意した。これにより、最初の条件が一致しない場合の複数のスキャンの問題が解決されます。ラムダのオーバーヘッドはどうですか?しかし、一度は多くありません。
Bruceboughton、2010

3
public static bool ContainsAny(this string haystack, IEnumerable<string> needles)
{
    return needles.Any(haystack.Contains);
}


2
// Nice method's name, @Dan Tao

public static bool ContainsAny(this string value, params string[] params)
{
    return params.Any(p => value.Compare(p) > 0);
    // or
    return params.Any(p => value.Contains(p));
}

Anyあらゆる人のAllために


2
    static void Main(string[] args)
    {
        string illegalCharacters = "!@#$%^&*()\\/{}|<>,.~`?"; //We'll call these the bad guys
        string goodUserName = "John Wesson";                   //This is a good guy. We know it. We can see it!
                                                               //But what if we want the program to make sure?
        string badUserName = "*_Wesson*_John!?";                //We can see this has one of the bad guys. Underscores not restricted.

        Console.WriteLine("goodUserName " + goodUserName +
            (!HasWantedCharacters(goodUserName, illegalCharacters) ?
            " contains no illegal characters and is valid" :      //This line is the expected result
            " contains one or more illegal characters and is invalid"));
        string captured = "";
        Console.WriteLine("badUserName " + badUserName +
            (!HasWantedCharacters(badUserName, illegalCharacters, out captured) ?
            " contains no illegal characters and is valid" :
            //We can expect this line to print and show us the bad ones
            " is invalid and contains the following illegal characters: " + captured));  

    }

    //Takes a string to check for the presence of one or more of the wanted characters within a string
    //As soon as one of the wanted characters is encountered, return true
    //This is useful if a character is required, but NOT if a specific frequency is needed
    //ie. you wouldn't use this to validate an email address
    //but could use it to make sure a username is only alphanumeric
    static bool HasWantedCharacters(string source, string wantedCharacters)
    {
        foreach(char s in source) //One by one, loop through the characters in source
        {
            foreach(char c in wantedCharacters) //One by one, loop through the wanted characters
            {
                if (c == s)  //Is the current illegalChar here in the string?
                    return true;
            }
        }
        return false;
    }

    //Overloaded version of HasWantedCharacters
    //Checks to see if any one of the wantedCharacters is contained within the source string
    //string source ~ String to test
    //string wantedCharacters ~ string of characters to check for
    static bool HasWantedCharacters(string source, string wantedCharacters, out string capturedCharacters)
    {
        capturedCharacters = ""; //Haven't found any wanted characters yet

        foreach(char s in source)
        {
            foreach(char c in wantedCharacters) //Is the current illegalChar here in the string?
            {
                if(c == s)
                {
                    if(!capturedCharacters.Contains(c.ToString()))
                        capturedCharacters += c.ToString();  //Send these characters to whoever's asking
                }
            }
        }

        if (capturedCharacters.Length > 0)  
            return true;
        else
            return false;
    }

1
メソッドHasWantedCharactersは、2つまたは3つの文字列を受け入れます。特定の文字を確認する最初の文字列。2番目の文字列、最初の文字列で検索するすべての文字。オーバーロードされたメソッドは、3番目の文字列として呼び出し元(つまりMain)に出力を提供します。ネストされたforeachステートメントは、ソース内の各文字を調べ、それを1つずつ比較します。私たちがチェックしているそれらの文字で。いずれかの文字が見つかった場合、trueを返します。オーバーロードされたメソッドは、チェックされたものと一致する文字列を出力しますが、すべてがなくなるまで戻りません。役に立ちましたか?
Nate Wilkins

1
C#コンソールプロジェクトを自由に開始し、プログラムクラス内のコードをコピーしてください。必ずmainメソッドを置き換えてください。2つの文字列(goodUserNameとbadUserName)をいじくり回すと、メソッドの機能とその機能がわかります。例は、コンマのような区切り文字なしで変更できる実行可能なソリューションを提供するために、より長くなっています。エスケープシーケンスは、単一引用符とバックスラッシュを確認する必要がある場合に、それらを表す1つの方法にすぎません。
ネイトウィルキンス


0

文字だけでなく任意の文字列を探している場合は、新しいプロジェクトNLibから文字列引数を受け取るIndexOfAnyのオーバーロードを使用できます。

if (s.IndexOfAny("aaa", "bbb", "ccc", StringComparison.Ordinal) >= 0)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.