顺序忽略重音字母

本文关键字:顺序 | 更新日期: 2023-09-27 18:32:20

我想要一个像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));
} 

但是,我收到此错误:

错误 2 方法的类型参数 'System.Linq.Enumerable.OrderBy<TSource,TKey>(System.Collections.Generic.IEnumerable, System.Func<Ts,TKey>, System.Collections.Generic.IComparer)' 无法从 用法。尝试显式指定类型参数。

似乎不喜欢StringComparer.我该如何解决这个问题?

注意:

我已经尝试从这里使用RemoveDiacritics(),但在这种情况下我不知道如何使用该方法。所以我试着做这样的事情,看起来也不错。

顺序忽略重音字母

OrderBykeySelector作为第一个参数。这个keySelector应该是一个Func<string,T>.因此,您需要一个方法,该方法采用字符串并返回枚举应作为排序依据的值

不幸的是,我不确定如何确定字符是否是"重音字母"。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 表达式接受一个字符串并返回相同的字符串,但将重音字母替换为空格。
OrderBy现在按这些字符串对枚举进行排序,因此"忽略"重音字母。

更新:如果您有一个工作方法RemoveDiacritics(string s)可以根据需要返回带有重音字母替换的字符串,您可以简单地像这样调用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);
}