Як я можу зробити порівняння рядків нечутливих до регістру?


217

Як я можу зробити рядок під регістром нечутливим?

drUser["Enrolled"] = 
      (enrolledUsers.FindIndex(x => x.Username == (string)drUser["Username"]) != -1);

Раніше сьогодні мені дали поради, які запропонували використовувати:

x.Username.Equals((string)drUser["Username"], StringComparison.OrdinalIgnoreCase)));

Проблема в тому, що я не можу це працювати, я спробував рядок нижче, це компілюється, але повертає неправильні результати, він повертає зареєстрованих користувачів як незареєстрованих, так і незареєстрованих користувачів як зареєстрованих.

drUser["Enrolled"] = 
      (enrolledUsers.FindIndex(x => x.Username.Equals((string)drUser["Username"], 
                                 StringComparison.OrdinalIgnoreCase)));

Хтось може вказати на проблему?


1
Який тип даних має drUser["Enrolled"]бути? Це схоже на булеве значення, але FindIndex()повертає індекс. Якщо індекс цього користувача дорівнює 0, він поверне 0, що може бути помилковим. Коли насправді це правда. Exists()Метод може бути краще в цьому випадку.
drharris

Ви впевнені, що в одному полі, який не знаходиться в іншому полі, немає часу для форматування чи додаткового простору?
joshlrogers

1
Я б запропонував використовувати enrollUsers.Any () замість FindIndex (і тестувати).
Марк

Відповіді:


405

Це не найкраща практика .NET Framework (4 & +) для перевірки рівності

String.Compare(x.Username, (string)drUser["Username"], 
                  StringComparison.OrdinalIgnoreCase) == 0

Використовуйте натомість наступне

String.Equals(x.Username, (string)drUser["Username"], 
                   StringComparison.OrdinalIgnoreCase) 

MSDN рекомендує:

  • Використовуйте перевантаження методу String.Equals, щоб перевірити, чи однакові дві струни.
  • Використовуйте методи String.Compare та String.CompareTo для сортування рядків, а не для перевірки рівності .

8
Ви повинні використовувати string.Compare, не String.Compare.
Фред

5
@Fred Я згоден, але чи можете ви визначити причину?
Гусдор

22
@Fred Я сподівався на технічну причину, а не на те, що «Stylecop каже так». Я щось пропускаю?
Гусдор

12
немає різниці string.comпорівняти з String.Compare, строкові синоніми класу System.String. і член Порівняти - це метод розширення. @ Fred @Gusdor
Нурі YILMAZ

23
@Gusdor stringє кращою практикою, ніж Stringоскільки це мовне ключове слово. Для одного це Stringможе бути щось інше System.String, а тоді, як stringбути не може. Крім того, stringбільш-менш гарантовано існування в C #, тоді Stringяк технічно є частиною .NET, а не C #.
Дейв Кузен

36

Ви повинні використовувати статичну String.Compareфункцію, як нижче

x => String.Compare (x.Username, (string)drUser["Username"],
                     StringComparison.OrdinalIgnoreCase) == 0

6
Ні, ви повинні використовувати String.Equalsзамість цього String.Compare. Не потрібно обчислювати, хто з них більший, лише щоб вони не були рівними.
ЕрікЕ

@ErikE: Цікаво, який метод ви рекомендуєте використовувати ще через 6 років :-)
Олег

3
Я не дивуюсь! Я впевнений, що рекомендую використовувати рівність, коли ви хочете семантику рівності, і використовувати порівняння, коли вам потрібно семантику порівняння. Що в цьому так складно? IEquatableі IComparableНЕ робіть те саме, і ви можете мати класи, які реалізують одне, але в якому НЕ було б сенсу реалізовувати інше. Наприклад, ви можете замовити вибірки датчиків за часом, без того, щоб жоден з них був рівним (Ізрівнянний). І ви можете вказати, чи рівні речі (IEquatable), але немає сенсу їх замовляти (скажімо, серійні номери комп'ютера).
ErikE

@ErikE: Ви не розумієте моєї точки зору. Старі відповіді відповідають часу написання. Не слід чіпати старих відповідей. Це правда про більшість продуктів. Найкраща практика або найкращий вибір з точки зору ефективності можуть бути змінені кілька разів пізніше. Я не бачу сенсу обговорювати будь-яку стару відповідь.
Олег

18
Вибачте, я сприйняв це як критику щодо правильності мого коментаря. Якщо ви говорите, що ви визнаєте, що ваша стара відповідь може бути не найкращою, то чудова! Однак я маю згоду з вами щодо старих відповідей. Старі відповіді, які дають погану інформацію, слід коментувати, їх слід оскаржувати, оскільки вони все ще інформують сьогоднішніх читачів.
ErikE

27

Будь ласка, використовуйте це для порівняння:

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

10
Просто пам’ятайте про переваги та помилки використання CurrentCultureIgnoreCase проти OrdinalIgnoreCase. Якщо вам не потрібна семантика порівняння культури, збережіть деякі показники та скористайтеся порядковим порівнянням.
ЕрікЕ

7

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

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

using System;

/// <summary>
/// String helpers.
/// </summary>
public static class StringExtensions
{
    /// <summary>
    /// Compares two strings, set ignoreCase to true to ignore case comparison ('A' == 'a')
    /// </summary>
    public static bool CompareTo(this string strA, string strB, bool ignoreCase)
    {
        return String.Compare(strA, strB, ignoreCase) == 0;
    }
}

Після цього все порівняння скорочується приблизно на 10 символів - порівняйте:

Перш ніж використовувати розширення String:

String.Compare(testFilename, testToStart,true) != 0

Після використання розширення String:

testFilename.CompareTo(testToStart, true)

2
Я не погоджуюся з називанням, порівняти - це добре відома функція в розробнику програмного забезпечення, і ви принципово змінили те, що вона робить. Я думаю, вам слід повернути цілий int, як порівняти, або змінити ім'я на щось інше, наприклад, "IsEqual".
Фред

7

Ви можете (хоча і навпаки) розширити, System.Stringщоб надати метод порівняння нечутливих до випадків порівняння:

public static bool CIEquals(this String a, String b) {
    return a.Equals(b, StringComparison.CurrentCultureIgnoreCase);
}

і використовувати як таке:

x.Username.CIEquals((string)drUser["Username"]);

C # дозволяє створювати методи розширення, які можуть слугувати синтаксисним цукром у вашому проекті.

Це не відповідь, і я знаю, що це питання давнє і вирішене, я просто хотів додати ці шматочки.


3

Думаю, ви знайдете більше інформації за цим посиланням:

http://codeidol.com/community/dotnet/controlling-case-sensibility-when-comparing-two-st/8873/

Для порівняння двох рядків використовуйте метод Порівняння статичного класу String. Чи є порівняння нечутливим до регістру, визначається третім параметром однієї з його перевантажень. Наприклад:

string lowerCase = "abc";
string upperCase = "AbC";
int caseInsensitiveResult = string.Compare(lowerCase, upperCase,
  StringComparison.CurrentCultureIgnoreCase);
int caseSensitiveResult = string.Compare(lowerCase,
  StringComparison.CurrentCulture);

Значення caseSensitiveResult дорівнює -1 (що вказує на те, що нижнєCase "менше, ніж" upperCase), а caseInsensitiveResult дорівнює нулю (що вказує, що нижнєCase "дорівнює" верхньомуCase).


1

Як щодо використання StringComparison.CurrentCultureIgnoreCaseнатомість?


5
-1: Ця відповідь недостатня. Дивіться відповідь @ ocean4dream: stackoverflow.com/a/13965429/109941 .
Джим Г.

@decyclone: ​​це повільніше, ніж OrdinalIgnoreCase, але, можливо, доречно в деяких випадках. Тому я не дам -1. stackoverflow.com/questions/2749662/…
Csaba Toth


1

Я хотів би написати метод розширення для EqualsIgnoreCase

public static class StringExtensions
{
    public static bool? EqualsIgnoreCase(this string strA, string strB)
    {
        return strA?.Equals(strB, StringComparison.CurrentCultureIgnoreCase);
    }
}

-11

ви завжди можете використовувати функції: .ToLower (); .ToUpper ();

конвертуйте свої рядки та порівняйте їх ...

Щасти


Я не думаю, що це вирішило б його проблему. Також зазначте, що це питання вже більше 4 років.
Vojtěch Dohnal

7
Це створює новий рядок, тому я вважаю це дуже неефективним. Оскільки для створення цього нового рядка всі символи будуть перевірені та перетворені на потрібний випадок, тоді порівняння має перевірити всі символи ще раз. Таким чином, вона використовує більше пам'яті та потужність обробки.
Air2

5
Це дуже погана практика через розподіл пам'яті.
Thorbjørn Lindeijer

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