Có một trường hợp C # không nhạy cảm toán tử bằng?


156

Tôi biết rằng sau đây là trường hợp nhạy cảm:

if (StringA == StringB) {

Vì vậy, có một toán tử sẽ so sánh hai chuỗi một cách không nhạy cảm?


có thể trùng lặp các chuỗi so sánh ngẫu nhiên trong C #
nawfal

Trong trường hợp ai đó vấp phải câu hỏi này để tìm kiếm một so sánh không nhạy cảm cho một Từ điển <chuỗi, int>, hãy xem câu hỏi này tại đây: Truy cập không nhạy cảm cho từ điển chung
Robotnik

Nó sẽ thực sự tốt đẹp; nói để xác định một tương ứng ~=với song song ==như một phiên bản không phân biệt chữ hoa chữ thường.
eidylon

Nếu các nhà phát triển của Microsoft thấy điều này, tôi nghĩ cần có một nhà điều hành không phân biệt chữ hoa chữ thường trong phiên bản tiếp theo của csharp. Chuỗi này.Equal () dài.
Rez.Net

Câu trả lời:


288

Thử cái này:

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

Tôi là người mới sử dụng StackOverflow tương đối - bạn có thể giải thích ý của bạn bằng cách thêm liên kết không? Bạn có nghĩa là các tài liệu MSDN?
John Femaleella

55
Nếu bạn muốn so sánh văn hóa nhạy cảm, sử dụng phương pháp này. Nếu bạn chỉ muốn đảm bảo "FILE" và "file" đều được chấp nhận, hãy sử dụng "OrdinalIgnoreCase" hoặc mã của bạn có thể không hoạt động ở những nơi như địa phương Thổ Nhĩ Kỳ. Để biết thêm thông tin, hãy xem moserware.com/2008/02/does-your-code-pass-turkey-test.html
Jeff Moser

10
Không chắc những gì Samuel đang nói về ... câu trả lời này là hoàn hảo. Nó chính xác và tự giải thích. Nó không cần tài liệu tham khảo. +1
Đi thuyền Judo

3
Argh đây là một câu nói kinh khủng! Bàn phím của tôi sẽ bị mòn. Đã qua rồi những ngày tôi có thể sử dụng " if A$=B$ then goto 10"
Sanjay Manohar

9
@Sanjay Manohar Sau đó viết một toán tử tùy chỉnh - và tôi muốn giới thiệu một bàn phím tốt hơn.
Rushyo

37

Cách tốt nhất để so sánh 2 chuỗi bỏ qua trường hợp của các chữ cái là sử dụng phương thức tĩnh String.Equals chỉ định so sánh chuỗi trường hợp bỏ qua thứ tự. Đây cũng là cách nhanh nhất, nhanh hơn nhiều so với chuyển đổi chuỗi thành chữ thường hoặc chữ hoa và so sánh chúng sau đó.

Tôi đã thử nghiệm hiệu suất của cả hai phương pháp và so sánh chuỗi trường hợp bỏ qua thứ tự nhanh hơn 9 lần ! Nó cũng đáng tin cậy hơn so với chuyển đổi chuỗi thành chữ thường hoặc chữ hoa (kiểm tra vấn đề i của Thổ Nhĩ Kỳ). Vì vậy, luôn luôn sử dụng phương thức String.Equals để so sánh các chuỗi cho đẳng thức:

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

Nếu bạn muốn thực hiện so sánh chuỗi văn hóa cụ thể, bạn có thể sử dụng mã sau:

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

Xin lưu ý rằng ví dụ thứ hai sử dụng logic so sánh chuỗi của văn hóa hiện tại, làm cho nó chậm hơn so với so sánh "trường hợp bỏ qua thứ tự" trong ví dụ đầu tiên, vì vậy nếu bạn không cần logic so sánh chuỗi cụ thể về văn hóa và bạn sau khi thực hiện tối đa, sử dụng so sánh "trường hợp bỏ qua thứ tự".

Để biết thêm thông tin, đọc toàn bộ câu chuyện trên blog của tôi .


1
Không đề xuất ToLowerhoặc ToLowerInvariant: họ tạo bộ nhớ chỉ để thực hiện so sánh và họ có thể thất bại khi các bộ ký tự mới được thêm vào unicode. ToUpperthất bại vì 'i' của Thổ Nhĩ Kỳ, trong số những người khác; không có lý do tại sao ToLowersẽ không thất bại trong tương lai vì những lý do tương tự.
antiduh

@antiduh, cảm ơn bạn đã bình luận. Hầu hết chúng ta đều nhận thức được những vấn đề tiềm ẩn này, nhiều hướng dẫn qua Internet đưa ra 'i' tiếng Thổ Nhĩ Kỳ làm ví dụ. Như bạn thấy trong bài viết của mình, tôi không khuyên bạn nên sử dụng ToLowerhoặc ToLowerInvariantphương pháp, tôi chỉ muốn cho thấy String.Equalsphương pháp này hiệu quả hơn bao nhiêu .
Pavel Vladov

3
"Hầu hết chúng ta đều nhận thức được những vấn đề tiềm ẩn này, nhiều hướng dẫn qua Internet đưa ra 'i' của Thổ Nhĩ Kỳ làm ví dụ" - không đủ người, và bạn vẫn đang đề cập đến nó như câu thứ hai trong câu trả lời của bạn. Hơn nữa, câu trả lời của bạn không bao gồm đủ biện minh để không bao giờ sử dụng nó - bạn chỉ cần đề cập đến hiệu suất; hiệu suất không phải luôn luôn là ưu tiên cuối cùng. Do đó, bạn hiện đang vi phạm các nguyên tắc của trung tâm trợ giúp; liên kết đến các trang web bên ngoài là tốt, nhưng bạn chưa tóm tắt nội dung đầy đủ (vấn đề của người Thổ Nhĩ Kỳ). SO không phải là nền tảng quảng cáo của bạn.
antiduh

20

Có một số thuộc tính trên StringComparerlớp tĩnh trả về các so sánh cho bất kỳ loại phân biệt chữ hoa chữ thường nào bạn muốn:

StringComparer Tính chất

Chẳng hạn, bạn có thể gọi

StringComparer.CurrentCultureIgnoreCase.Equals(string1, string2)

hoặc là

StringComparer.CurrentCultureIgnoreCase.Compare(string1, string2)

Nó sạch hơn một chút so với string.Equalshoặc string.Comparequá tải cần StringComparisontranh luận.


15
System.Collections.CaseInsensitiveComparer

hoặc là

System.StringComparer.OrdinalIgnoreCase

Điều này có ảnh hưởng đến toàn bộ ứng dụng không?
GateKiller

3
Tôi có thể tìm thêm thông tin về điều này ở đâu. Điều này có nghĩa là tôi có thể sử dụng == cho trường hợp khớp không nhạy cảm?
GateKiller

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

8

hoặc là

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

nhưng bạn cần chắc chắn rằng StringA không phải là null. Vì vậy, có lẽ tốt hơn sử dụng tu:

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

như John đề nghị

EDIT: đã sửa lỗi


4

Bạn có thể dùng

if (stringA.equals(StringB, StringComparison.CurrentCultureIgnoreCase))

3

Nhà điều hành? KHÔNG, nhưng tôi nghĩ bạn có thể thay đổi văn hóa của mình để so sánh chuỗi không phân biệt chữ hoa chữ thường.

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

Tôi tự tin rằng nó sẽ thay đổi cách các chuỗi được so sánh bởi toán tử bằng.


Vâng, để nói rằng ít nhất nó hoàn toàn không phải là những gì bạn muốn làm trừ khi bạn muốn tất cả các so sánh chuỗi không phân biệt chữ hoa chữ thường. Nhưng tôi nghĩ nó thay đổi hành vi của toán tử bằng.
John Leidegren

3

Đây là một ý tưởng để đơn giản hóa cú pháp:

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

Có thể sử dụng như:

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

Mặc dù tôi thích cú pháp sử dụng tìm kiếm rõ ràng , nhưng nó hơi sai lệch ( IgnoreCasevs IgnoreCaseString) và mơ hồ (Java chọn ẩn unboxing so với đấm bốc ngầm vì vậy tôi tin rằng điều này sẽ không hoạt động trong Java với hàm ẩn trong chuỗi đó). Và điều này tạo ra chi phí bộ nhớ của 2 đối tượng mới với thực thi cây cuộc gọi cho mỗi so sánh nhảy vào một số lệnh gọi phương thức lồng nhau cho trường hợp sử dụng được hiển thị. Điều đó nói rằng, đối với hầu hết các trường hợp, hiệu suất có thể là đủ tốt.
Arkaine55

Mặc dù đây là một ý tưởng thông minh , nhưng nó không thực sự khôn ngoan từ góc độ bảo trì. Bạn đang tạo một loại chuỗi thay thế một cách hiệu quả thay vì sử dụng loại chuỗi tích hợp sẵn của hệ thống. Lập trình viên đến sau sẽ không hiểu những gì đang diễn ra trong nháy mắt và sau đó anh ấy / cô ấy sẽ chửi rủa bạn. Sử dụng chuỗi.Equals () thực sự không tệ lắm và hầu hết mọi người sẽ hiểu những gì nó đang làm.
ntcolonel

1

Tôi đã quá quen với việc gõ vào cuối các phương thức so sánh này: , StringComparison.

Vì vậy, tôi đã thực hiện một phần mở rộng.

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

Chỉ cần lưu ý rằng bạn sẽ cần kiểm tra null thisStringtrước khi gọi máy lẻ.


1
Đây có giống như phương thức tích hợp này trong các phiên bản .NET Framework hiện tại không? docs.microsoft.com/en-gb/dotnet/api/ từ
Bernard Vander Beken 27/03/18

1
Xuất hiện như vậy. Có vẻ như các phiên bản sau của .net bao gồm điều này ngay bây giờ.
Valamas

Có sẵn từ .NET 4.5 và tất cả các phiên bản .NET Core.
Bernard Vander Beken


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

Mọi người báo cáo ToUpperInvariant () nhanh hơn ToLowerInvariant ().


1
Bất biến có thể là một ý tưởng tồi nếu văn hóa hiện tại hoặc mong muốn có các quy tắc đặc biệt cho lớp vỏ trên.
OregonGhost

Điều này có tạo ra một bản sao mới của mỗi chuỗi không? Nếu vậy, ý tưởng tồi.
cjk

1
Điều này cũng sẽ đưa ra một ngoại lệ nếu một trong hai (hoặc cả hai) chuỗi là null.
tvanfosson

3
Hiệu suất khôn ngoan, đây không phải là một giải pháp tốt vì bạn cũng sẽ tạo 2 trường hợp chuỗi mới ở đây.
Frederik Gheysels 13/03/2016

0

Những câu trả lời khác hoàn toàn hợp lệ ở đây, nhưng bằng cách nào đó, bạn phải mất một thời gian để nhập StringComparison.OrdinalIgnoreCasevà sử dụng String.Compare.

Tôi đã mã hóa phương thức mở rộng Chuỗi đơn giản, trong đó bạn có thể chỉ định nếu so sánh là phân biệt chữ hoa chữ thường hay chữ hoa chữ thường với boolean - xem câu trả lời sau:

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.