มีตัวดำเนินการที่ไม่คำนึงถึงตัวพิมพ์ใหญ่เท่ากับ C # หรือไม่


156

ฉันรู้ว่าต่อไปนี้เป็นกรณี ๆ ไป:

if (StringA == StringB) {

ดังนั้นมีผู้ประกอบการซึ่งจะเปรียบเทียบสองสายในลักษณะที่ไม่รู้สึก?


มีความเป็นไปได้ที่ซ้ำกันของการเปรียบเทียบสตริงใน C #
nawfal

ในกรณีที่มีคนสะดุดคำถามนี้เพื่อค้นหาการเปรียบเทียบแบบตัวเล็กและเล็กสำหรับ Dictionary <string, int> ให้ดูที่คำถามนี้ที่นี่: การเข้าถึงแบบตัวพิมพ์เล็กและใหญ่สำหรับพจนานุกรมทั่วไป
Robotnik

มันจะดีจริงๆ พูดเพื่อกำหนดที่สอดคล้อง~=กับขนาน==เป็นรุ่นที่ไม่ตรงตามตัวพิมพ์ใหญ่ - เล็ก
eidylon

หากนักพัฒนาของ Microsoft เห็นสิ่งนี้ฉันคิดว่ามีความต้องการตัวดำเนินการแบบตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ในรุ่นถัดไปของ csharp สตริงนี้ Equal () มีความยาว
Rez.Net

คำตอบ:


288

ลองสิ่งนี้:

string.Equals(a, b, StringComparison.CurrentCultureIgnoreCase);

ฉันเป็นมือใหม่ของ StackOverflow คุณสามารถอธิบายความหมายของการเพิ่มลิงค์ได้ไหม? คุณหมายถึงเอกสาร MSDN หรือไม่
John Feminella

55
หากคุณต้องการเปรียบเทียบวัฒนธรรมที่ละเอียดอ่อนใช้วิธีนี้ หากคุณเพียงต้องการให้แน่ใจว่าทั้งสองยอมรับ "ไฟล์" และ "ไฟล์" ให้ใช้ "OrdinalIgnoreCase" หรือรหัสของคุณอาจไม่ทำงานในสถานที่ต่าง ๆ เช่นโลแคลตุรกี สำหรับข้อมูลเพิ่มเติมโปรดดูที่moserware.com/2008/02/does-your-code-pass-turkey-test.html
เจฟฟ์ Moser

10
ไม่แน่ใจว่าซามูเอลกำลังพูดถึงอะไร ... คำตอบนี้สมบูรณ์แบบ มันถูกต้องและอธิบายตนเอง มันไม่จำเป็นต้องอ้างอิง +1
แล่นเรือใบยูโด

3
นี่มันช่างน่ารังเกียจจริงๆ! แป้นพิมพ์ของฉันจะเสื่อมสภาพ วันนี้เป็นวันที่ฉันสามารถใช้ " if A$=B$ then goto 10"
Sanjay Manohar

9
@Sanjay Manohar จากนั้นเขียนโอเปอเรเตอร์ที่กำหนดเอง - และฉันขอแนะนำคีย์บอร์ดที่ดีกว่า
Rushyo

37

วิธีที่ดีที่สุดในการเปรียบเทียบ 2 สตริงโดยไม่สนใจขนาดตัวพิมพ์ใหญ่คือการใช้วิธีสตริง String.Equalsคงที่ระบุการเปรียบเทียบสตริงสตริงกรณีที่ไม่สนใจ นี่เป็นวิธีที่เร็วที่สุดเร็วกว่าการแปลงสตริงเป็นตัวพิมพ์เล็กหรือตัวใหญ่และเปรียบเทียบมันหลังจากนั้น

ฉันทดสอบประสิทธิภาพของทั้งสองวิธีและการเปรียบเทียบสตริงตัวพิมพ์เล็กและตัวพิมพ์เล็กนั้นเร็วกว่า 9 เท่า ! นอกจากนี้ยังมีความน่าเชื่อถือมากกว่าการแปลงสตริงเป็นตัวพิมพ์เล็กหรือตัวพิมพ์ใหญ่ (ดูปัญหาภาษาตุรกี i) ดังนั้นให้ใช้วิธีการString.Equalsเสมอเพื่อเปรียบเทียบสตริงเพื่อความเท่าเทียมกัน:

String.Equals(string1, string2, StringComparison.OrdinalIgnoreCase);

หากคุณต้องการทำการเปรียบเทียบสตริงเฉพาะวัฒนธรรมคุณสามารถใช้รหัสต่อไปนี้:

String.Equals(string1, string2, StringComparison.CurrentCultureIgnoreCase);

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

สำหรับข้อมูลเพิ่มเติมอ่านเรื่องเต็มบนบล็อกของฉัน


1
ไม่แนะนำToLowerหรือToLowerInvariant: พวกเขาสร้างหน่วยความจำเพียงเพื่อทำการเปรียบเทียบและพวกเขาอาจล้มเหลวในขณะที่ชุดอักขระใหม่จะถูกเพิ่มลงใน Unicode ToUpperล้มเหลวเนื่องจากตุรกี 'i' และอื่น ๆ ไม่มีเหตุผลใดที่ToLowerจะไม่ล้มเหลวในอนาคตด้วยเหตุผลที่คล้ายคลึงกัน
antiduh

@antiduh ขอบคุณสำหรับความคิดเห็นของคุณ พวกเราส่วนใหญ่ตระหนักถึงปัญหาที่อาจเกิดขึ้นเหล่านี้แบบฝึกหัดมากมายทางอินเทอร์เน็ตให้ตัวอย่าง 'i' ของตุรกี ในขณะที่คุณเห็นในโพสต์ของฉันฉันไม่แนะนำให้ใช้ToLowerหรือToLowerInvariantวิธีการฉันแค่อยากจะแสดงให้เห็นว่ามีประสิทธิภาพมากขึ้นString.Equalsวิธีการคือ
Pavel Vladov

3
"พวกเราส่วนใหญ่ตระหนักถึงปัญหาที่อาจเกิดขึ้นเหล่านี้บทเรียนจำนวนมากทางอินเทอร์เน็ตให้ตัวอย่าง 'i' ของตุรกี" - มีคนไม่มากพอและคุณยังพูดถึงมันเป็นประโยคที่สองในคำตอบของคุณ นอกจากนี้คำตอบของคุณยังไม่มีเหตุผลเพียงพอที่จะไม่ใช้ - คุณเพียงกล่าวถึงประสิทธิภาพ ประสิทธิภาพไม่ได้เป็นความสำคัญสูงสุดเสมอไป ดังนั้นคุณกำลังละเมิดหลักเกณฑ์ของศูนย์ช่วยเหลือ ลิงก์ไปยังเว็บไซต์ภายนอกนั้นใช้ได้ แต่คุณไม่ได้สรุปเนื้อหาอย่างเพียงพอ (ปัญหาตุรกี 'i') ดังนั้นไม่ใช่แพลตฟอร์มโฆษณาของคุณ
antiduh

20

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

StringComparer คุณสมบัติ

ตัวอย่างเช่นคุณสามารถโทร

StringComparer.CurrentCultureIgnoreCase.Equals(string1, string2)

หรือ

StringComparer.CurrentCultureIgnoreCase.Compare(string1, string2)

มันค่อนข้างสะอาดกว่าstring.Equalsหรือstring.Compareโอเวอร์โหลดที่StringComparisonโต้แย้งกัน


15
System.Collections.CaseInsensitiveComparer

หรือ

System.StringComparer.OrdinalIgnoreCase

มีผลกับแอปพลิเคชันทั้งหมดหรือไม่
GateKiller

3
ฉันจะหาข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ได้ที่ไหน นี่หมายความว่าฉันสามารถใช้ == สำหรับการแข่งขันที่ไม่ตอบสนองต่อกรณีหรือไม่
GateKiller


8

หรือ

if (StringA.Equals(StringB, StringComparison.CurrentCultureIgnoreCase)) {

แต่คุณต้องแน่ใจว่า StringA ไม่ใช่โมฆะ ดังนั้นอาจใช้ tu ดีกว่า:

string.Equals(StringA , StringB, StringComparison.CurrentCultureIgnoreCase);

ตามที่จอห์นแนะนำ

แก้ไข: แก้ไขข้อผิดพลาด



3

ผู้ประกอบการ? ไม่ แต่ฉันคิดว่าคุณสามารถเปลี่ยนวัฒนธรรมของคุณเพื่อให้การเปรียบเทียบสตริงไม่ได้ตรงตามตัวพิมพ์ใหญ่ - เล็ก

// you'll want to change this...
System.Threading.Thread.CurrentThread.CurrentCulture
// and you'll want to custimize this
System.Globalization.CultureInfo.CompareInfo

ฉันมั่นใจว่ามันจะเปลี่ยนวิธีการเปรียบเทียบสตริงโดยตัวดำเนินการเท่ากับ


ใช่ที่จะบอกว่าอย่างน้อยที่สุดมันไม่ใช่สิ่งที่คุณต้องการทำอย่างเต็มที่เว้นแต่ว่าคุณต้องการให้การเปรียบเทียบสตริงทั้งหมดไม่ตรงตามตัวพิมพ์ใหญ่ - เล็ก แต่ฉันคิดว่ามันเปลี่ยนพฤติกรรมของตัวดำเนินการเท่ากับ
John Leidegren

3

นี่เป็นแนวคิดที่จะทำให้ไวยากรณ์ง่ายขึ้น:

public class IgnoreCase
{
    private readonly string _value;

    public IgnoreCase(string s)
    {
        _value = s;
    }

    protected bool Equals(IgnoreCase other)
    {
        return this == other;
    }

    public override bool Equals(object obj)
    {
        return obj != null &&
               (ReferenceEquals(this, obj) || (obj.GetType() == GetType() && this == (IgnoreCase) obj));
    }

    public override int GetHashCode()
    {
        return _value?.GetHashCode() ?? 0;
    }

    public static bool operator ==(IgnoreCase a, IgnoreCase b)
    {
        return string.Equals(a, b, StringComparison.OrdinalIgnoreCase);
    }

    public static bool operator !=(IgnoreCase a, IgnoreCase b)
    {
        return !(a == b);
    }

    public static implicit operator string(IgnoreCase s)
    {
        return s._value;
    }

    public static implicit operator IgnoreCase(string s)
    {
        return new IgnoreCase(s);
    }
}

ใช้งานได้เช่น:

Console.WriteLine((IgnoreCase) "a" == "b"); // false
Console.WriteLine((IgnoreCase) "abc" == "abC"); // true
Console.WriteLine((IgnoreCase) "Abc" == "aBc"); // true
Console.WriteLine((IgnoreCase) "ABC" == "ABC"); // true

ในขณะที่ฉันชอบไวยากรณ์การใช้ที่ดูสะอาดตามันเป็นความเข้าใจผิดเล็กน้อย ( IgnoreCasevs IgnoreCaseString) และคลุมเครือ (Java เลือกการชกมวย unboxing โดยปริยาย vs Java ดังนั้นฉันเชื่อว่าสิ่งนี้จะไม่ทำงานใน Java ด้วยการส่งกลับโดยนัยในสตริง) และสิ่งนี้จะสร้างโอเวอร์เฮดของหน่วยความจำของวัตถุใหม่ 2 ชิ้นโดยมีการเรียกใช้ทรีทรีสำหรับการเปรียบเทียบแต่ละครั้งจะกระโดดไปยังเมธอดซ้อนหลายแบบสำหรับกรณีการใช้งานที่แสดง ที่กล่าวมาสำหรับกรณีส่วนใหญ่ประสิทธิภาพอาจดีพอ
Arkaine55

แม้ว่านี่จะเป็นความคิดที่ฉลาดแต่ก็ไม่ฉลาดนักจากมุมมองการบำรุงรักษา คุณกำลังสร้างประเภทสตริงตัวแทนแทนที่จะใช้ชนิดสตริงในตัวของระบบ โปรแกรมเมอร์ที่มาไม่เข้าใจว่าเกิดอะไรขึ้นอย่างรวดเร็วจากนั้นเขา / เธอจะสบประมาทคุณ การใช้ string.Equals () ไม่ใช่สิ่งที่เลวร้ายจริงๆและคนส่วนใหญ่จะเข้าใจว่ามันกำลังทำอะไรอยู่
ntcolonel

1

ฉันคุ้นเคยกับการพิมพ์ที่ส่วนท้ายของวิธีการเปรียบเทียบเหล่านี้: , StringComparison.

ดังนั้นฉันจึงขยาย

namespace System
{   public static class StringExtension
    {
        public static bool Equals(this string thisString, string compareString,
             StringComparison stringComparison)
        {
            return string.Equals(thisString, compareString, stringComparison);
        }
    }
}

เพียงแค่ทราบว่าคุณจะต้องตรวจสอบ null thisStringก่อนโทร ext


1
นี่เป็นวิธีการในตัวใน. NET Framework เวอร์ชันปัจจุบันหรือไม่ docs.microsoft.com/en-gb/dotnet/api/…
Bernard Vander Beken

1
ปรากฏว่า ดูเหมือนว่า. net เวอร์ชันที่ใหม่กว่าจะรวมอยู่ในขณะนี้
Valamas

มีให้ตั้งแต่. NET 4.5 และ. NET Core ทุกเวอร์ชัน
Bernard Vander Beken


0
if (StringA.ToUpperInvariant() == StringB.ToUpperInvariant()) {

ผู้คนรายงาน ToUpperInvariant () เร็วกว่า ToLowerInvariant ()


1
ค่าคงที่อาจเป็นความคิดที่ไม่ถูกต้องหากวัฒนธรรมปัจจุบันหรือที่ต้องการมีกฎพิเศษสำหรับโครงตัวบน
OregonGhost

สิ่งนี้สร้างสำเนาใหม่ของแต่ละสตริงหรือไม่ ถ้าเป็นเช่นนั้นความคิดที่ไม่ดี
cjk

1
สิ่งนี้จะทำให้เกิดข้อยกเว้นหากสตริง (หรือทั้งสอง) เป็นโมฆะ
tvanfosson

3
ประสิทธิภาพนั้นไม่ได้เป็นวิธีแก้ปัญหาที่ดีเนื่องจากคุณจะสร้างอินสแตนซ์สตริงใหม่ 2 รายการที่นี่เช่นกัน
Frederik Gheysels

0

อื่น ๆ คำตอบที่ถูกต้องทั้งหมดที่นี่ แต่อย่างใดมันต้องใช้เวลาในการพิมพ์และยังมีการใช้StringComparison.OrdinalIgnoreCaseString.Compare

ฉันเขียนรหัสวิธีการขยายสตริงอย่างง่ายซึ่งคุณสามารถระบุได้ว่าการเปรียบเทียบนั้นตรงตามตัวพิมพ์ใหญ่หรือตัวพิมพ์เล็กหรือใหญ่โดยใช้บูลีนหรือไม่ - ดูคำตอบต่อไปนี้:

https://stackoverflow.com/a/49208128/2338477

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.