วิธีตรวจสอบว่า String มีสตริงใดบ้าง


104

ฉันต้องการตรวจสอบว่าสตริง s มี "a" หรือ "b" หรือ "c" ใน C # หรือไม่ ฉันกำลังมองหาวิธีแก้ปัญหาที่ดีกว่าการใช้

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

1
สำหรับกรณีที่ซับซ้อนให้ค้นหาtrieโครงสร้างข้อมูล
ตัวแปรที่น่าสังเวช

คำตอบ:


46

หากคุณกำลังมองหาอักขระเดี่ยวคุณสามารถใช้String.IndexOfAny()ไฟล์.

หากคุณต้องการสตริงตามอำเภอใจฉันไม่ทราบวิธีการ. NET เพื่อให้บรรลุ "โดยตรง" แม้ว่านิพจน์ทั่วไปจะใช้งานได้


98

มีสิ่งนี้เสมอ:

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

อย่างไรก็ตามไม่มีสิ่งใดที่จะตรงกับประสิทธิภาพของสาย||การเปรียบเทียบของคุณ


14
การเพิ่มไวยากรณ์สั้น ๆ ใหม่ให้กับโซลูชันที่ดีนี้ public static bool ContainsAny(this string haystack, params string[] needles) { return needles.Any(haystack.Contains); }
simonkaspers1

วิธีแก้ปัญหาที่ง่ายและชัดเจน แต่มีการใช้งานที่พร้อมใช้งานที่ดีที่ไม่ต้องใช้การวนซ้ำหลายครั้งผ่านสตริงฟางหรือไม่ ฉันสามารถใช้งานได้ด้วยตัวเองทำซ้ำผ่านอักขระสตริงกองหญ้าและเปรียบเทียบอักขระตัวแรกของเข็มตามลำดับในคราวเดียว แต่ฉันไม่อยากจะเชื่อเลยว่าโซลูชันที่ไม่สำคัญดังกล่าวยังไม่ได้ใช้ในไลบรารี NuGet ที่รู้จักกันดี
RollerKostr

@RollerKostr มันไม่ได้สร้างไว้ใน C # (เลย) ทำไมต้องเพิ่มการอ้างอิงเพิ่มเติมในโครงการของคุณสำหรับวิธีง่ายๆเช่นนี้?
jmdon

75

นี่คือโซลูชัน LINQ ซึ่งแทบจะเหมือนกัน แต่ปรับขนาดได้มากกว่า:

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

3
นั่นคือปรับขนาดได้ในแง่ที่ง่ายต่อการเพิ่มตัวละครไม่ใช่ในแง่ของการแสดง ... :)
Guffa

2
ใช่แน่นอน บางที "ขยายได้มากกว่า" อาจเป็นตัวเลือกคำที่ดีกว่า
Jeff Mercado

ประสิทธิภาพจะไม่แย่มาก ดีกว่า regexp ที่ตีความ แต่อย่างใด
Steven Sudit

คำตอบที่ยอดเยี่ยมเพียงเพื่อความสมบูรณ์คุณสามารถแยกสตริงขาเข้าของคุณออกเป็นอาร์เรย์ก่อนเช่น var splitStringArray = someString.Split (''); จากนั้นคุณสามารถทำบางสิ่งเช่น if (someStringArray.Any (s => otherString.Contains (s))) {// do something} หวังว่าจะช่วยให้ใครบางคนได้รับความกระจ่าง
Tahir Khalid


21

คุณสามารถลองใช้นิพจน์ทั่วไป

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

1
+1 แม้ว่าเขากำลังมองหาตัวอักษรเดี่ยวโซลูชัน linq หรือ indexOfAny อาจมีประสิทธิภาพมากกว่า
Joel Coehoorn

+1 สำหรับนิพจน์ทั่วไป นั่นคือสิ่งที่ฉันจะไปถ้าไม่มี IndexOfAny
Stavros

1
นิพจน์ทั่วไปเกินความจำเป็นสำหรับสิ่งนี้
Steven Sudit

3
อะไรทำให้คนพูดว่า regexes มากเกินไปสำหรับเรื่องนี้? หาก regex ถูกคอมไพล์ครั้งเดียวและใช้หลายครั้งและคุณมีสตริงที่มีเพียง c อยู่ในนั้นหรือ c ใกล้จุดเริ่มต้นและ a, b ใกล้จุดสิ้นสุด regex จะมีประสิทธิภาพมากขึ้น
bruceboughton

ใช้ไม่ได้กับอักขระพิเศษเช่น -, "". `=
MAFAIZ

17

หากคุณต้องการมีรายการที่เฉพาะเจาะจงStringComparison(ตัวอย่างเช่นการละเว้นตัวพิมพ์เล็กและใหญ่) คุณสามารถใช้วิธีการขยายสตริงนี้

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.

3
เพียงบันทึกเดียวเพื่อปรับปรุงคำตอบนี้ คุณสามารถเขียนมันได้ดียิ่งขึ้นด้วยคีย์เวิร์ด params: ประกอบด้วยAny (อินพุตสตริงนี้, StringComparisonarisonType, params string [] containsKeywords) และใช้เช่น input.ContainsAny (substrings, StringComparison.CurrentCultureIgnoreCase, "string", "many substrings" ... ฯลฯ )
Roma Borodov

8

นี่เป็น "โซลูชันที่ดีกว่า" และค่อนข้างง่าย

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


4

เนื่องจากสตริงเป็นชุดของอักขระคุณสามารถใช้วิธีการขยาย LINQ ได้:

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

การดำเนินการนี้จะสแกนสตริงหนึ่งครั้งและหยุดที่การเกิดครั้งแรกแทนที่จะสแกนสตริงหนึ่งครั้งสำหรับแต่ละอักขระจนกว่าจะพบการจับคู่

นอกจากนี้ยังสามารถใช้สำหรับนิพจน์ใด ๆ ที่คุณต้องการเช่นตรวจสอบช่วงของอักขระ:

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

เห็นด้วย วิธีนี้ช่วยแก้ปัญหาการสแกนหลายครั้งเมื่อเงื่อนไขแรกไม่ตรงกัน สงสัยว่าค่าใช้จ่ายของแลมด้าคืออะไร? ไม่ควรมากครั้งเดียว
bruceboughton


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 ยอมรับสองหรือสามสตริง สตริงแรกที่เราต้องการตรวจสอบอักขระบางตัว สตริงที่สองอักขระทั้งหมดที่เราจะค้นหาในสตริงแรก เมธอดโอเวอร์โหลดให้เอาต์พุตไปยังผู้เรียก (เช่น Main) เป็นสตริงที่สาม คำสั่ง foreach ที่ซ้อนกันจะผ่านอักขระแต่ละตัวในแหล่งที่มาและเปรียบเทียบทีละตัว ด้วยอักขระเหล่านั้นที่เรากำลังตรวจสอบ หากพบอักขระตัวใดตัวหนึ่งจะส่งคืนจริง เมธอดที่โอเวอร์โหลดจะแสดงสตริงของอักขระที่พบว่าตรงกับที่ถูกตรวจสอบ แต่จะไม่ส่งคืนจนกว่าจะหมด เป็นประโยชน์?
Nate Wilkins

1
อย่าลังเลที่จะเริ่มโครงการคอนโซล C # และคัดลอกรหัสภายในคลาสโปรแกรมอย่าลืมแทนที่วิธีหลัก Tinker ที่มีสองสตริง (goodUserName และ badUserName) และคุณอาจเห็นว่าวิธีการนี้ทำอย่างไรและทำงานอย่างไร ตัวอย่างมีความยาวมากขึ้นเพื่อให้เป็นโซลูชันที่ใช้งานได้ซึ่งสามารถแก้ไขได้โดยไม่ต้องใช้ตัวคั่นเช่นเครื่องหมายจุลภาค ลำดับ Escape เป็นเพียงวิธีหนึ่งในการแสดงเครื่องหมายอัญประกาศเดี่ยวและแบ็กสแลชหากคุณต้องการตรวจสอบ
Nate Wilkins


0

หากคุณกำลังมองหาสตริงตามอำเภอใจไม่ใช่แค่อักขระคุณสามารถใช้ IndexOfAny ที่มากเกินไปซึ่งใช้อาร์กิวเมนต์สตริงจากNLibโปรเจ็กต์ใหม่:

if (s.IndexOfAny("aaa", "bbb", "ccc", StringComparison.Ordinal) >= 0)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.