Bir dizenin bazı dizelerden herhangi birini içerip içermediğini kontrol etme


104

Bir String s'nin C # içinde "a" veya "b" veya "c" içerip içermediğini kontrol etmek istiyorum. Kullanmaktan daha güzel bir çözüm arıyorum

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

1
Karmaşık durumlar için trieveri yapısına bakın.
Miserable Variable

Yanıtlar:


46

Tek karakter arıyorsanız, kullanabilirsiniz String.IndexOfAny().

Rasgele dizeler istiyorsanız, o zaman bunu "doğrudan" elde etmek için bir .NET yönteminin farkında değilim, ancak normal bir ifade işe yarayabilir.


98

Her zaman şu vardır:

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

    return false;
}

Kullanım:

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

||Bununla birlikte , karşılaştırma zincirinizin performansıyla hiçbir şey eşleşmeyecektir .


14
Bu güzel çözüme yeni kısa sözdizimi public static bool ContainsAny(this string haystack, params string[] needles) { return needles.Any(haystack.Contains); }
ekleniyor

Basit ve açık çözüm. Ancak haystack dizesi aracılığıyla birden fazla yineleme gerektirmeyen kullanıma hazır herhangi bir iyi uygulama var mı? Bunu kendi başıma uygulayabilirim, samanlık dize karakterlerini yineleyerek ve sırayla iğnelerin ilk karakterlerini tek seferde karşılaştırabilirim, ancak bu tür önemsiz çözümün henüz iyi bilinen NuGet kitaplıklarında uygulanmadığına inanamıyorum.
RollerKostr

@RollerKostr (Henüz) C # içinde yerleşik değil, öyleyse neden bu kadar basit bir çözüm için projenize ek bağımlılıklar ekleyesiniz?
jmdon

75

İşte hemen hemen aynı olan ancak daha ölçeklenebilir olan bir LINQ çözümü:

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

3
Bu, performans anlamında değil, karakter eklemenin kolay olması anlamında ölçeklenebilir ... :)
Guffa

2
Ah evet, elbette. Belki de "daha genişletilebilir" daha iyi bir kelime seçimi olurdu.
Jeff Mercado

Performans korkunç olmayacak. Yine de yorumlanmış bir normal ifadeden daha iyi.
Steven Sudit

Sadece eksiksizlik için harika bir cevap, gelen dizinizi önce bir diziye bölebilirsiniz, örneğin: var splitStringArray = someString.Split (''); O zaman şöyle bir şey yapabilirsiniz: if (someStringArray.Any (s => otherString.Contains (s))) {// bir şeyler yap} Birinin anlaşılır olması için yardımcı olmasını umuyoruz.
Tahir Halid


21

Normal ifadeyle deneyebilirsiniz

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

1
+1, ancak tek karakter aradığı için linq çözümü veya indexOfAny daha verimli olabilir.
Joel Coehoorn

Normal ifade için +1. IndexOfAny olmasaydı bunun için gidebilirdim
Stavros

1
Düzenli ifadeler bunun için gereğinden fazla.
Steven Sudit

3
İnsanlara normal ifadelerin bunun için aşırı olduğunu söyleten nedir? Normal ifade bir kez derlenmişse ve birden çok kez kullanılmışsa ve içinde yalnızca c veya başlangıca yakın c ve sona yakın a, b dizeleri varsa, normal ifade çok daha verimli olur.
bruceboughton

-, "." =
MAFAIZ

17

Belirli bir ContainsAny'ye ihtiyacınız varsa StringComparison(örneğin, durumu yok saymak için), bu String Extentions yöntemini kullanabilirsiniz.

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

İle kullanım 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.

3
Bu cevabı geliştirmek için sadece bir not. Params anahtar kelimesi ile daha da ellegant yazabilirsiniz: ContainsAny (bu dize girişi, StringComparison ComparType, params string [] containsKeywords) ve input.ContainsAny gibi (alt dizeler, StringComparison.CurrentCultureIgnoreCase, "string", "birçok alt dizi" gibi) kullanabilirsiniz ... vb)
Roma Borodov

8

Bu "daha güzel bir çözüm" ve oldukça basit

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

5
List<string> includedWords = new List<string>() { "a", "b", "c" };
bool string_contains_words = includedWords.Exists(o => s.Contains(o));

4

Bir dize bir karakter koleksiyonu olduğundan, bunlarda LINQ uzantı yöntemlerini kullanabilirsiniz:

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

Bu, dizeyi bir kez tarar ve bir eşleşme bulunana kadar dizeyi her karakter için bir kez taramak yerine ilk görüldüğünde durur.

Bu, istediğiniz herhangi bir ifade için de kullanılabilir, örneğin bir dizi karakterin kontrol edilmesi:

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

Kabul. Bu, ilk koşullar eşleşmediğinde çoklu tarama sorununu çözer. Acaba lambda'nın tepesi ne? Yine de çok fazla olmamalı.
bruceboughton

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

Anyherhangi biri Alliçin, her biri için


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 yöntemleri iki veya üç dizeyi kabul eder. Belirli karakterleri kontrol etmek istediğimiz ilk dize. İkinci dize, ilkinde arayacağımız tüm karakterler. Aşırı yüklenmiş yöntem, üçüncü dizge olarak çağırana (yani Ana) çıktı sağlar. İç içe geçmiş bir foreach ifadesi, kaynaktaki her karakterden geçer ve onu tek tek karşılaştırır; aradığımız karakterlerle. Karakterlerden biri bulunursa true döndürür. Aşırı yüklenmiş yöntem, kontrol edilenlerle eşleşen bulunan bir karakter dizesi üretir, ancak tümü bitene kadar geri dönmez. Faydalı?
Nate Wilkins

1
Bir C # konsol projesi başlatmaktan ve kodu program sınıfının içine kopyalamaktan çekinmeyin - ana yöntemi değiştirdiğinizden emin olun. İki dizeyle (goodUserName ve badUserName) düzeltin ve yöntemlerin ne işe yaradığını ve nasıl çalıştığını görebilirsiniz. Örnekler, virgül gibi sınırlayıcılar olmadan değiştirilebilen uygulanabilir bir çözüm sağlamak için daha uzundur. Kaçış dizileri, kontrol etmeniz gerekiyorsa, tek tırnak ve ters eğik çizgiyi temsil etmenin yalnızca bir yoludur.
Nate Wilkins

1

Normal İfadeler kullanabilirsiniz

if(System.Text.RegularExpressions.IsMatch("a|b|c"))

Elbette yapabilirsin, ama neredeyse her şey daha iyi olduğunda neden bunu isteyeceğini anlamıyorum.
Steven Sudit

0

Yalnızca karakterleri değil, gelişigüzel dizeler arıyorsanız, yeni NLib projesinden dize bağımsız değişkenleri alan bir IndexOfAny aşırı yüklemesi kullanabilirsiniz :

if (s.IndexOfAny("aaa", "bbb", "ccc", StringComparison.Ordinal) >= 0)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.