ตรวจสอบว่าสตริงมีอักขระหนึ่งใน 10 ตัวหรือไม่


108

ฉันใช้ C # และฉันต้องการตรวจสอบว่าสตริงมีอักขระหนึ่งในสิบตัวหรือไม่, *, &, # ฯลฯ เป็นต้น

วิธีที่ดีที่สุดคืออะไร?


1
คุณต้องการดูว่ามีอักขระใดหรือไม่หรือมีอักขระ "หนึ่งตัว" (เช่น: ตัวเดียว) ของอักขระเหล่านั้นและมีเพียงตัวเดียว
Reed Copsey

คำตอบ:


211

ต่อไปนี้เป็นวิธีที่ง่ายที่สุดในมุมมองของฉัน:

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

หรือในรูปแบบที่อ่านง่ายกว่า:

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

ขึ้นอยู่กับบริบทและประสิทธิภาพที่ต้องการคุณอาจต้องการหรือไม่ต้องการแคชอาร์เรย์ถ่าน


เมื่อสร้างอินสแตนซ์อาร์เรย์ char ชนิดอาจถูกละเว้นและจะถูกอนุมาน
Palec

41

อย่างที่คนอื่นบอกให้ใช้ IndexOfAny อย่างไรก็ตามฉันจะใช้วิธีนี้:

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

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

ด้วยวิธีนี้คุณจะไม่ต้องสร้างอาร์เรย์ใหม่ในการโทรแต่ละครั้ง นอกจากนี้สตริงยังสแกนได้ง่ายกว่าชุดของตัวอักษร IMO

แน่นอนว่าหากคุณจะใช้สิ่งนี้เพียงครั้งเดียวดังนั้นการสร้างที่สูญเปล่าจึงไม่ใช่ปัญหาคุณสามารถใช้:

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

ขึ้นอยู่กับว่าคุณคิดว่าอ่านได้ง่ายขึ้นว่าคุณต้องการใช้อักขระเครื่องหมายวรรคตอนที่อื่นหรือไม่และจะเรียกวิธีการนี้บ่อยเพียงใด


แก้ไข: นี่คือทางเลือกที่จะใช้วิธีการ Reed Copsey สำหรับหาว่าสตริงมีตรงหนึ่งของตัวละคร

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

ฉันคิดว่ามันคุ้มค่าที่จะแคชอาร์เรย์ถ่านหากประสิทธิภาพเป็นปัญหา แต่อีกครั้งอาจไม่คุ้มค่าขึ้นอยู่กับบริบท
Noldorin

1
ใช่ถ้าคุณใช้เพียงวิธีเดียวที่จะถูกดำเนินการครั้งเดียวอาจไม่คุ้มค่า อย่างไรก็ตามฉันคิดว่ามันช่วยเพิ่มความสามารถในการอ่านและประสิทธิภาพ คุณสามารถใช้ToCharArrayแบบฟอร์ม "อินไลน์" ได้หากจำเป็น
Jon Skeet

1
@canon: ชุดใหญ่แค่ไหน? สำหรับชุดเล็กมาก ๆ ฉันคาดหวังว่า Array จะเร็วกว่า สำหรับชุดใหญ่ HashSet มีแนวโน้มที่จะชนะด้วยไมล์
Jon Skeet

5

หากคุณต้องการดูว่ามีอักขระหรือไม่ขอแนะนำให้ใช้ string.IndexOfAny ตามที่แนะนำไว้ที่อื่น

หากคุณต้องการตรวจสอบว่าสตริงมีอักขระหนึ่งในสิบตัวและมีเพียงตัวเดียวก็จะซับซ้อนขึ้นเล็กน้อย ฉันเชื่อว่าวิธีที่เร็วที่สุดคือตรวจสอบกับทางแยกจากนั้นตรวจสอบรายการที่ซ้ำกัน

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

ใช่ - ฉันคิดว่าการวนรอบเดียวน่าจะเร็วกว่าในกรณีนี้โดยเฉพาะอย่างยิ่งกับเครื่องหมายวรรคตอนเล็ก ๆ ฉันอยากรู้ให้ลองทดสอบด้วยสตริงขนาดใหญ่เพื่อดูว่าอันไหนเร็วกว่ากัน
Reed Copsey

1
ฉันคิดว่าการหาจุดตัดของทั้งสองสตริงนั้นจะต้องไปทีละอักขระดังนั้นฉันจึงไม่เห็นว่ามันจะเร็วขึ้นได้อย่างไร ... และเส้นทางที่แนะนำของฉันไม่เพียง แต่ใช้พาสเดียว แต่ยังมี ตัวเลือกของ "ก่อนกำหนด" ลองนึกภาพว่าข้อความมีความยาวเป็นล้านอักขระ แต่สองตัวแรกเป็น "*" ทั้งคู่ :)
Jon Skeet


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" มันจะจับคู่กับราคา ... แทนที่จะอ้างอิงวิธีที่เหมาะสมวิธีหนึ่งในการ ตรวจหาสกุลเงินที่กำหนดไว้ที่นี่: stackoverflow.com/questions/7214513/…
mcse3010
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.