OrderBy 忽略重音字母

OrderBy ignoring accented letters

我想要一种像 OrderBy() 这样的方法,它总是命令忽略带重音的字母并将它们视为非重音字母。我已经尝试覆盖 OrderBy() 但似乎我不能这样做,因为那是一个静态方法。

所以现在我想为 OrderBy() 创建一个自定义 lambda 表达式,如下所示:

public static IOrderedEnumerable<TSource> ToOrderBy<TSource, TKey>(
    this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
    if(source == null)
        return null;

    var seenKeys = new HashSet<TKey>();

    var culture = new CultureInfo("pt-PT");
    return source.OrderBy(element => seenKeys.Add(keySelector(element)), 
                          StringComparer.Create(culture, false));
} 

但是,我遇到了这个错误:

Error 2 The type arguments for method 'System.Linq.Enumerable.OrderBy<TSource,TKey>(System.Collections.Generic.IEnumerable<TSource>, System.Func<TSource,TKey>, System.Collections.Generic.IComparer<TKey>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

好像不喜欢StringComparer。我该如何解决这个问题?

注:

我已经尝试使用 here but I don't know how to use that method in this case. So I tried to do something like this 中的 RemoveDiacritics(),这看起来也不错。

OrderBykeySelector 作为第一个参数。这个keySelector应该是一个Func<string,T>。因此,您需要一个方法,该方法接受一个字符串和 returns 一个 值,您的枚举应按该值进行排序 .

不幸的是,我不确定如何确定一个字符是否为 "accented letter"。 RemoveDiacritics 不适用于我的 é

因此,假设您有一个名为 IsAccentedLetter 的方法来确定字符是否为重音字母:

public bool IsAccentedLetter(char c)
{
    // I'm afraid this does NOT really do the job
    return CharUnicodeInfo.GetUnicodeCategory(c) == UnicodeCategory.NonSpacingMark;
}

因此您可以这样对列表进行排序:

string[] myStrings = getStrings(); // whereever your strings come from
var ordered = myStrings.OrderBy(s => new string(s.Select(c => 
    IsAccentedLetter(c) ? ' ' : c).ToArray()), StringComparer.Create(culture, false));

lambda 表达式接受一个字符串和 returns 相同的字符串,但用空 space.
替换重音字母 OrderBy 现在按这些字符串对您的枚举进行排序,"ignores" 重音字母也是如此。

更新: 如果你有一个工作方法 RemoveDiacritics(string s) returns 根据需要替换带重音字母的字符串,你可以简单地调用 OrderBy 像这样:

string[] mystrings = getStrings();
var ordered = myStrings.OrderBy(RemoveDiacritics, StringComparer.Create(culture, false));

已解决!我收到该错误是因为要使用 StringComparer 元素在 OrderBy() 表达式中排序,该元素需要是 string.

因此,当我知道该元素是一个字符串时,我将其转换为一个字符串,并使用 RemoveDiacritics() 方法忽略重音字母并将它们视为非重音字母。

public static IOrderedEnumerable<TSource> ToOrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
    if(!source.SafeAny())
        return null;

    return source.OrderBy(element => Utils.RemoveDiacritics(keySelector(element).ToString()));
}

为了保证 RemoveDiacritics() 正常工作,我添加了 HtmlDecode() 行。

public static string RemoveDiacritics(string text)
{
    if(text != null)
        text = WebUtility.HtmlDecode(text);

    string formD = text.Normalize(NormalizationForm.FormD);
    StringBuilder sb = new StringBuilder();

    foreach (char ch in formD)
    {
        UnicodeCategory uc = CharUnicodeInfo.GetUnicodeCategory(ch);
        if (uc != UnicodeCategory.NonSpacingMark)
        {
            sb.Append(ch);
        }
    }

    return sb.ToString().Normalize(NormalizationForm.FormC);
}