文字列に10文字のいずれかが含まれているかどうかを確認する


107

C#を使用していて、文字列に*、&、#などの10文字のいずれかが含まれているかどうかを確認したい

最良の方法は何ですか?


1
そこに文字が含まれているかどうか、またはそれらに「1」(つまり、1つだけ)の文字が含まれていて、1つだけ含まれているかどうかを確認しますか?
リードコプシー、

回答:


210

以下は私の見解では最も簡単な方法です:

var match = str.IndexOfAny(new char[] { '*', '&', '#' }) != -1

または、おそらく読みやすい形式で:

var match = str.IndexOfAny("*&#".ToCharArray()) != -1

必要なコンテキストとパフォーマンスに応じて、char配列をキャッシュしたい場合としない場合があります。


char配列をインスタンス化する場合、型は省略され、推測されます。
Palec、

40

他の人が言ったように、IndexOfAnyを使用します。ただし、次のように使用します。

private static readonly char[] Punctuation = "*&#...".ToCharArray();

public static bool ContainsPunctuation(string text)
{
    return text.IndexOfAny(Punctuation) >= 0;
}

そうすれば、呼び出しごとに新しい配列を作成することにはなりません。文字列は、一連の文字リテラルIMOよりもスキャンが簡単です。

もちろん、これを1回だけ使用するので、無駄な作成が問題にならない場合は、次のいずれかを使用できます。

private const string Punctuation = "*&#...";

public static bool ContainsPunctuation(string text)
{
    return text.IndexOfAny(Punctuation.ToCharArray()) >= 0;
}

または

public static bool ContainsPunctuation(string text)
{
    return text.IndexOfAny("*&#...".ToCharArray()) >= 0;
}

それは、どれがより読みやすくなるか、句読点文字を他の場所で使用するかどうか、およびメソッドが呼び出される頻度に依存します。


編集:これは、文字列に文字が1つだけ含まれているかどうかを調べるためのリードコプシーの方法の代替方法です。

private static readonly HashSet<char> Punctuation = new HashSet<char>("*&#...");

public static bool ContainsOnePunctuationMark(string text)
{
    bool seenOne = false;

    foreach (char c in text)
    {
        // TODO: Experiment to see whether HashSet is really faster than
        // Array.Contains. If all the punctuation is ASCII, there are other
        // alternatives...
        if (Punctuation.Contains(c))
        {
            if (seenOne)
            {
                return false; // This is the second punctuation character
            }
            seenOne = true;
        }
    }
    return seenOne;
}

パフォーマンスに問題がある場合はchar配列をキャッシュする価値があると思いますが、コンテキストによっては価値がない場合もあります。
ノルドリン2009

1
はい、一度実行するメソッドでのみ使用する場合は、価値がないかもしれません。ただし、読みやすさだけでなくパフォーマンスも向上すると思います。ToCharArrayもちろん、必要に応じて「インライン」の形式を使用できます。
ジョンスキート

1
@canon:セットの大きさは?非常に小さなセットの場合、Array.Containsの方が高速になると思います。大規模なセットの場合、HashSetは何マイルも勝つ可能性があります。
Jon Skeet、2015

5

文字が含まれているかどうかを確認するだけの場合は、他の場所で提案されているように、string.IndexOfAnyを使用することをお勧めします。

文字列に10文字のうち1文字だけが含まれていることを確認したい場合は、少し複雑になります。交差点をチェックしてから重複をチェックするのが最も速い方法だと思います。

private static char[] characters = new char [] { '*','&',... };

public static bool ContainsOneCharacter(string text)
{
    var intersection = text.Intersect(characters).ToList();
    if( intersection.Count != 1)
        return false; // Make sure there is only one character in the text

    // Get a count of all of the one found character
    if (1 == text.Count(t => t == intersection[0]) )
        return true;

    return false;
}

ええ-私はこの場合、特に句読点の数が少ない場合、単一のループの方がおそらく速いと思います。大きな文字列でこれをテストして、どれが本当に速いかを知りたいと思います。
リードコプシー

1
とにかく、2つの文字列の交点を見つけることは、文字ごとに行わなければならないので、どのように速くなるかわかりません...そして、私の提案されたルートは、単一のパスを使用するだけでなく、 「早期終了」のオプション。テキストは万字長い場合を想像しますが、最初の二つは両方とも「*」です:)
ジョンスキート


1
var specialChars = new[] {'\\', '/', ':', '*', '<', '>', '|', '#', '{', '}', '%', '~', '&'};

foreach (var specialChar in specialChars.Where(str.Contains))
{
    Console.Write(string.Format("string must not contain {0}", specialChar));
}

0

あなた方全員に感謝します!(そして主にジョン!):これにより私はこれを書くことができました:

    private static readonly char[] Punctuation = "$€£".ToCharArray();

    public static bool IsPrice(this string text)
    {
        return text.IndexOfAny(Punctuation) >= 0;
    }

特定の文字列が実際に「価格が低すぎて表示できない」などの価格または文であるかどうかを検出する良い方法を探していたので。


2
私はこれが古いことを知っていますが、明確にするためにこれは通貨を一致させるための特に良い方法ではありません...誰かが「Ke $ ha」と書いた場合、それは価格として一致します...代わりに1つの適切な方法を参照してください:通貨がここで定義された検出stackoverflow.com/questions/7214513/...
mcse3010
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.