2009-09-08 14 views
36

Zastanawiam się, jaki jest właściwy sposób porównania dwóch postaci ignorujących przypadek, który zadziała dla wszystkich kultur. Czy najlepszym sposobem na przetestowanie dwóch znaków bez ignorowania przypadku jest również Comparer<char>.Default? Czy to działa dla par zastępczych?Jaki jest prawidłowy sposób porównania char ignorowanie przypadku?

EDIT: Dodano próbka IComparer<char> realizacja

Jeśli to pomaga każdemu to, co ja postanowiłem wykorzystać

public class CaseInsensitiveCharComparer : IComparer<char> { 
    private readonly System.Globalization.CultureInfo ci; 
    public CaseInsensitiveCharComparer(System.Globalization.CultureInfo ci) { 
     this.ci = ci; 
    } 
    public CaseInsensitiveCharComparer() 
     : this(System.Globalization.CultureInfo.CurrentCulture) { } 
    public int Compare(char x, char y) { 
     return Char.ToUpper(x, ci) - Char.ToUpper(y, ci); 
    } 
} 

// Prints 3 
Console.WriteLine("This is a test".CountChars('t', new CaseInsensitiveCharComparer())); 
+0

ToUpper char może konwertować do odpowiedniego górnego przypadku w odniesieniu do obecnego hodowli, ale kolejność słownikowa zwrócone nie jest prawidłowe. Być może jest to obsługiwane tylko w .NET dla porównań łańcuchów. – Holstebroe

Odpowiedz

63

To zależy co masz na myśli przez „praca za al l kultury ". Czy chciałbyś, aby "ja" i "ja" były równe nawet w Turcji?

Można użyć:

bool equal = char.ToUpperInvariant(x) == char.ToUpperInvariant(y); 

... ale nie jestem pewien, czy to „działa” zgodnie z wszystkich kultur poprzez zrozumienie „prace”.

Oczywiście można skonwertować oba znaki do ciągów, a następnie wykonać dowolne porównanie na łańcuchach. Nieco mniej wydajne, ale to nie daje cały szereg porównań dostępnych w ramach:

bool equal = x.ToString().Equals(y.ToString(), 
           StringComparison.InvariantCultureIgnoreCase); 

Dla par zastępczych, o Comparer<char> nie będzie możliwe w każdym razie, bo nie masz pojedynczy char . Możesz jednak utworzyć Comparer<int>.

+0

Tak właśnie myślałem o zrobieniu tego w obu twoich przykładach, ale pomyślałem, że mógł istnieć lepszy sposób, o którym nie wiedziałem, że istnieje framework. Zastanawiam się w kontekście metody rozszerzenia LINQ dla String.Contains (char, IEqualityComparer ) –

+1

Nie ma żadnej metody ramowej do tego: porównywanie ciągów jest faktycznie realizowane za pomocą natywnych metod, a nie przez obniżanie do implementacji Comparer . –

+0

@TimSchmelter: Nie, udało mi się ominąć tego z jakiegoś powodu. Dodano krótką notatkę na końcu. –

1

string.Compare ("String", "String" true)

To będzie pracować dla każdej struny

+1

Witam sergio, szukam sposobu na porównanie dwóch instancji char, a nie instancji napisów. Szukam implementacji Comparer , która ignoruje wielkość liter. –

+8

Działa to doskonale w krajach anglojęzycznych. Jednak nikt w Europie Wschodniej nigdy nie skorzysta z aplikacji, którą piszesz. –

+2

@Jon Grant: Używam tego w moim kraju (Portugalia), portugalski jest językiem łacińskim, który ma wiele "dziwnych" znaków, takich jak: ã é ç, to działa idealnie dla mnie. – Sergio

12

Korzystanie z domyślnego (czyli nie niezmienna) kultura:

if (char.ToLower(ch1) == char.ToLower(ch2)) 
{ .... } 

lub określić Kultura:

CultureInfo myCulture = ...; 
if (char.ToLower(ch1, myCulture) == char.ToLower(ch2, myCulture)) 
{ .... } 
+0

Nie mogę poddać pod głosowanie, ale oddałem głos, ponieważ uważam, że twoje rozwiązanie jest odpowiednio dobrane. –

+0

To nie jest odpowiedź na pytanie. –

+0

Jon, zgodził się, ale przeczytałem "to będzie działać dla wszystkich kultur" jako trochę zbyt optymistyczne i nierealistyczne. Powinienem był powiedzieć to, co oczywiste. –

2

Jak rozumiem, nie jest tak naprawdę sposób, że będzie "działać dla wszystkich kultur". Albo chcesz porównać znaki dla jakiegoś wewnętrznego, nie wyświetlanego do użytkownika powodu (w takim przypadku powinieneś użyć InvariantCulture), albo chcesz użyć CurrentCulture użytkownika. Oczywiście korzystanie z aktualnej kultury użytkownika oznacza, że ​​otrzymasz różne wyniki w różnych lokalizacjach, ale będą one zgodne z oczekiwaniami użytkowników w tych lokalizacjach.

Nie wiedząc więcej o tym, DLACZEGO porównujesz dwie postacie, naprawdę nie mogę ci doradzić, z której strony powinieneś skorzystać.

+0

Dzięki Jon, to ogólne pytanie, nie jestem dobrze zorientowany w unicode i pomyślałem, że postawię tutaj pytanie. Rozważmy metodę rozszerzenia String.Contains (char, IEqualityComparer ), którą zapewnia LINQ, jaki byłby właściwy sposób implementacji, która nie uwzględnia wielkości liter? –

+0

Ponownie, to naprawdę zależy od danych i dlaczego je porównujesz. Chcielibyśmy, na przykład, posortować rzeczy w pewną spójną kolejność, stosując dowolne z niezmiennych porównań byłoby w porządku. Jeśli reagujesz na dane wprowadzane przez użytkownika, prawdopodobnie chcesz wykorzystać kulturę tego użytkownika, aby uzyskać wyniki, których oczekują. Nie jestem pewien, czy naprawdę istnieje odpowiedź "jeden rozmiar dla wszystkich". –

+0

Czy uważasz, że moja implementacja programu Comparer dostarczona jako odpowiedź byłaby poprawnym podejściem? –

0

można spróbować:

class Test{ 
    static int Compare(char t, char p){ 
     return string.Compare(t.ToString(), p.ToString(), StringComparison.CurrentCultureIgnoreCase); 
    } 
} 

Ale wątpię, to jest „optymalny” sposób to zrobić, ale nie jestem wszystkich przypadkach trzeba być sprawdzanie ...

0

Co ja myślałem, że będzie dostępny w czasie pracy jest czymś następującym

public class CaseInsensitiveCharComparer : IComparer<char> { 
    private readonly System.Globalization.CultureInfo ci; 
    public CaseInsensitiveCharComparer(System.Globalization.CultureInfo ci) { 
     this.ci = ci; 
    } 
    public CaseInsensitiveCharComparer() 
     : this(System.Globalization.CultureInfo.CurrentCulture) { } 
    public int Compare(char x, char y) { 
     return Char.ToUpper(x, ci) - Char.ToUpper(y, ci); 
    } 
} 

// Prints 3 
Console.WriteLine("This is a test".CountChars('t', new CaseInsensitiveCharComparer())); 
+1

Niebezpiecznie jest przyjąć, że porównanie znaków przez odejmowanie będzie nadal poprawne w przyszłych wersjach CLR, więc użyłbym 'return Char.ToUpper (x, ci) .CompareTo (Char.ToUpper (y, ci));' zamiast . –

+0

@MattHowells Twierdzę, że ... zobacz char.CompareTo (char) ':' return (m_value-value); ' –

0

Polecam porównanie wielkimi literami, a jeśli nie odpowiadają one następnie porównując małymi literami, na wszelki wypadek uppercasing narodowa a logika niższej logiki zachowuje się nieco inaczej.

Dodatek

Przykładowo

int CompareChar(char c1, char c2) 
{ 
    int dif; 

    dif = char.ToUpper(c1) - char.ToUpper(c2); 
    if (diff != 0) 
     dif = char.ToLower(c1) - char.ToLower(c2); 
    return dif; 
} 
Powiązane problemy