Чи є оператор C # нечутливий дорівнює оператору?


156

Я знаю, що до регістру належить:

if (StringA == StringB) {

Так чи є оператор, який порівняє два рядки нечутливим чином?



Якщо хтось наткнеться на це запитання, шукаючи порівняння з невідчутними для Словника словника <string, int>, перегляньте це питання тут: Нечутливий доступ до справи для загального словника
— Robotnik

Було б справді приємно; скажімо, щоб визначити відповідну ~=паралелі ==як нечутливу до регістру версію.
— ейдилон

Якщо розробники Microsoft бачать це, я думаю, що в наступній версії csharp необхідний оператор, нечутливий до регістру. Цей рядок.Equal () є тривалим.
— Рез.Нет

Відповіді:


288

Спробуйте це:

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

Я родич StackOverflow - я можу пояснити, що ви маєте на увазі, додавши посилання? Ви маєте на увазі документи MSDN?
— Джон Фемінелла

55
Якщо ви хочете порівняти з культурою порівняння, використовуйте цей метод. Якщо ви просто хочете переконатися, що "FILE" і "file" прийняті, скористайтеся "OrdinalIgnoreCase", інакше ваш код може не працювати в таких місцях, як турецькі мови. Більше інформації див. У розділі moserware.com/2008/02/does-your-code-pass-turkey-test.html
— Джефф Мозер

10
Не впевнений, про що говорить Самуїл ... ця відповідь ідеальна. Його правильне і самоосмислене. Він не потребує посилань. +1
— Плавання по дзюдо

3
Аарг, це така жахлива рота! моя клавіатура зношується Пройшли дні, коли я можу використовувати " if A$=B$ then goto 10"
— Санджай Манохар

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не вдається через турецьке «я», серед інших; немає жодних причин, чому б в ToLowerмайбутньому не вийшло з подібних причин.
— антидух

@antiduh, дякую за ваш коментар. Більшість із нас знають про ці потенційні проблеми, багато навчальних посібників в Інтернеті дають приклад турецького «я». Як ви бачите у своєму дописі, я не рекомендую використовувати ToLowerчи ToLowerInvariantметоди, я просто хотів показати, наскільки ефективніший String.Equalsметод.
— Павло Владов

3
"Більшість із нас знають про ці потенційні проблеми. Багато навчальних посібників в Інтернеті дають турецьке" я "як приклад" - людей недостатньо, і ви все ще згадуєте це як друге речення у своїй відповіді. Крім того, ваша відповідь не містить достатнього обґрунтування, щоб ніколи її не використовувати - ви просто згадуєте про ефективність; виконання не завжди є першочерговим завданням. Як наслідок, Ви зараз порушуєте правила довідкового центру; посилання на зовнішні веб-сайти чудові, але ви недостатньо не узагальнили вміст (проблема "я"). Так не ваша рекламна платформа.
— антидух

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 не є нульовим. Тому, ймовірно, краще використовувати ту:

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

як запропонував Джон

EDIT: виправлено помилку



3

Оператор? НІ, але я думаю, ви можете змінити свою культуру, щоб порівняння рядків не залежно від регістру.

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

Я впевнений, що це змінить спосіб порівняння рядків оператором рівних.


Так, принаймні, це зовсім не те, що ви хотіли б зробити, якщо ви не хочете, щоб всі порівняння рядків були нечутливими до регістру. Але я думаю, це змінює поведінку оператора рівних.
— Джон Лейдегрен

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 вибирає неявне розпакування та неявне боксування, тому я вважаю, що це не буде працювати в 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перед тим, як викликати доб.


1
Це те саме, що і цей вбудований метод у поточних версіях .NET Framework? docs.microsoft.com/en-gb/dotnet/api/…
— Бернар Вандер Став

1
Виявляється так. Схоже, новіші версії .net включають це зараз.
— Валамас

Доступний з .NET 4.5 та всіх версій .NET Core.
— Бернард Вандер Став


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

Люди повідомляють, що ToUpperInvariant () швидше, ніж ToLowerInvariant ().


1
Інваріант може бути поганою ідеєю, якщо в нинішній чи бажаній культурі є спеціальні правила щодо верхнього корпусу.
— OregonGhost

Чи створює це нову копію кожного рядка? Якщо так, погана ідея.
— cjk

1
Це також призведе до виключення, якщо будь-який (або обидва) рядки є недійсними.
— tvanfosson

3
Це означає, що це не дуже вдале рішення, оскільки ви також створите два нові рядкові екземпляри і тут.
— Фредерік Гейселс

0

Інші відповіді тут цілком справедливі, але певний час, StringComparison.OrdinalIgnoreCaseа також використання потрібен певний час String.Compare.

Я зашифрував простий метод розширення String, де ви могли вказати, чи порівняння є регістровим чи регістровим без букву з булевим - див. Наступну відповідь:

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.