it-roy-ru.com

Как правильно сравнивать регистр символов?

Мне интересно, как правильно сравнивать два символа, игнорируя регистр, который будет работать для всех культур. Кроме того, Comparer<char>.Default лучший способ проверить два символа без учета регистра? Это работает для суррогатных пар?

EDIT: Добавлен пример реализации IComparer<char>

Если это кому-нибудь поможет, то это то, что я решил использовать

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()));
46
Brett Ryan

Это зависит от того, что вы подразумеваете под «работой для всех культур». Хотели бы вы, чтобы «я» и «я» были равны даже в Турции?

Вы можете использовать:

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

... но я не уверен, что это "работает" в соответствии со всеми культурами по вашему пониманию "работ".

Конечно, вы можете преобразовать оба символа в строки, а затем выполнить любое сравнение строк. Несколько менее эффективный, но он дает вам весь спектр сравнений, доступных в фреймворке:

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

Для суррогатных пар Comparer<char> в любом случае не будет выполнимым, потому что у вас нет единственной char. Вы можете создать Comparer<int> хотя.

78
Jon Skeet

Используя стандартную (то есть не / инвариантную) культуру: 

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

Или укажите культуру:

CultureInfo myCulture = ...;
if (char.ToLower(ch1, myCulture) == char.ToLower(ch2, myCulture))
{  ....  }
13
Henk Holterman

Насколько я понимаю, на самом деле не существует способа, который "работал бы для всех культур". Либо вы хотите сравнить символы по какой-то внутренней причине, не отображаемой пользователю (в этом случае вам следует использовать InvariantCulture), либо вы хотите использовать CurrentCulture пользователя. Очевидно, что использование текущей культуры пользователя будет означать, что вы получите разные результаты в разных локалях, но они будут соответствовать ожиданиям ваших пользователей в этих локалях.

Не зная больше о ПОЧЕМУ вы сравниваете два символа, я не могу по-настоящему посоветовать вам, какой из них вы должны использовать. 

2
Jon Grant

string.Compare ("string a", "STRING A", true)

Это будет работать для каждой строки

1
Sergio

То, что я думал, что будет доступно во время выполнения, примерно так:

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
Brett Ryan

Я бы порекомендовал сравнивать прописные буквы, а если они не совпадают, сравнивать строчные, на случай, если логика верхнего и нижнего регистров локали будет немного отличаться.

Приложение

Например,

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;
}
0
David R Tribble

Вы можете попробовать:

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

Но я сомневаюсь, что это «оптимальный» способ сделать это, но я не во всех случаях нужно проверять ...

0
ahawker