OrderBy 忽略重音字母
Posted
技术标签:
【中文标题】OrderBy 忽略重音字母【英文标题】:OrderBy ignoring accented letters 【发布时间】:2016-05-05 19:53:57 【问题描述】:我想要一个像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
(System.Collections.Generic.IEnumerable , System.Func , System.Collections.Generic.IComparer )' 不能从 用法。尝试明确指定类型参数。
似乎不喜欢StringComparer
。我该如何解决这个问题?
注意:
我已经尝试使用here 中的RemoveDiacritics()
,但我不知道在这种情况下如何使用该方法。所以我尝试做类似this 之类的东西,看起来也不错。
【问题讨论】:
你使用的是 Linq2Sql 还是 LinqObjects ? HashSet 是干什么用的? 【参考方案1】:解决了!我收到这个错误是因为要使用 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);
【讨论】:
绝对没有必要实现你的ToOrderBy
。如果你有一个名为mystrings
的字符串枚举,你可以简单地调用mystrings.OrderBy(RemoveDiacritics, StringComparer.Create(culture, false))
@RenéVogt 我知道,但我想表现出来,因为我的项目很大,我不想在所有项目中进行修改
@RenéVogt 在我的解决方案中使用 ToOrderBy()
我只需要执行 Ctrl + F 并将 .OrderBy(
替换为 .ToOrderBy(
并且将来如果我需要更改此逻辑中的某些内容,我只需需要在一个地方而不是在整个项目中进行更改。这是我的表演。对于例外情况,我有一个 SafeAny()
方法,我检查它是否不为空并且有任何元素。【参考方案2】:
OrderBy
将keySelector
作为第一个参数。这个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));
【讨论】:
这个逻辑给了我错误'TSource' does not contain a definition for 'Select' and no extension method 'Select' accepting a first argument of type 'TSource' could be found (are you missing a using directive or an assembly reference?)
。此外,您正在用空格替换重音字母,我希望将重音字母视为非重音字母。
@Ninita 哦,这是一个误会:我的 source´ was meant to be your original list. I did not intend to implement my own
ToOrderBy` 扩展名,这没有必要!在您的解决方案中,您不需要您的ToOrderBy
,您只需致电mystrings.OrderBy(RemoveDiacritics, StringComparer,Create(culture, false)
以上是关于OrderBy 忽略重音字母的主要内容,如果未能解决你的问题,请参考以下文章
ORDERBY "human" 使用 SQL 字符串操作的字母顺序