一个简单的代码示例,让我们尝试对俄语字符数组进行排序:
var a = new char[]
{
'д',
'е',
'ё',
'ж'
};
var b = a.OrderBy(x => x).ToList();
Console.WriteLine(string.Concat(b));
这个简单的代码乍一看会给出一些意想不到的东西дежё,但这里的 c# 恰好符合标准,因为字母ё的代码比俄语字母表中所有其他字母的代码都大。
让我们尝试对一个字符串数组进行排序,其中一个字符串包含字母ё:
var a = new string[]
{
"жар",
"дом",
"ели",
"ёлка",
};
var b = a.OrderBy(x => x).ToList();
Console.WriteLine(string.Join(" ", b));
我们得到了我们所期望дом ели ёлка жар的。这些行似乎按预期排序。
让我们尝试ели替换为ель. 我们会好起来的дом ёлка ель жар。显然,在对字符串进行排序时,e和e被认为是一个字符,在第二种情况下ёлка它变成 beforeель因为k在b之前。
我对提议的字符串数组排序算法的天真理解表明它应该使用与字符数组排序相同的字符代码比较算法。这显然不会发生。算法的预期修改是考虑到俄语字母表中的ё仍然不在 unicode 中的位置这一事实。但实际上,我们有一个实现,其中e和e是一个字符。
我对几个问题感兴趣。字符串排序算法具体定义在哪里?我通过 ReferenceSource 的旅程将我带到了 GitHub CLR 的某个地方,我不确定我是否在朝着正确的方向前进。为什么决定将e和ё用于一个字符,而不是实施公平排序?是某人的任性决定还是仍然在某些规范中定义?
我了解并非所有问题都意味着社区普通成员的明确回答,但我在此提及。
或者也许我误解了一切,如果是这样的话请纠正我。
谢谢你。
在这里,让你惊讶的不是BCL算法的奇怪,而是Unicode标准的实现。
Unicode® Technical Standard #10 / Unicode Collation Algorithm文档指出(我的翻译):
于是,词的比较进行如下:
和。等等
对于俄语,根据“填字游戏原则”,Yo被认为是E的重音变体,Y是I的重音变体。
我希望在 Unicode 中选择俄语标准能够得到语言学家的同意。
如何在 .NET 中更改它 - 如何强制E被视为位于E和F之间的单独字母,我不会马上说。(但请参阅相邻的答案。)
顺便说一下,一个或另一个 Unicode 标准的实现不是语言的特性,而是系统的特性。BCL 要求系统比较字符串,以免复制 Unicode 实现。这意味着相同的程序,当安装在 Windows 7 和 Windows 10 上时,在排序方面可能会有不同的行为。
澄清
对于俄语语言环境, Y被认为是AND的单独字母,而对于英语,Y被认为是AND的重音版本。There 和 There的字母Yo都被认为是 E 的重音版本。例子:
产生这个结果:
故事的寓意:对字符串进行排序时,请始终指定语言环境!
除了@VladD 的回答:
或者,您可以实现自己的
IComparer,例如:字符串比较是逐个字符进行的,比较中涉及的字符在 中指定
symbols,按所需的升序排列,不在的字符将symbols被忽略。在方法本身
Compare中,我们首先进行不区分大小写的比较,如果产生相同的结果,我们进行区分大小写的比较。这种行为是可以改变的。如果您想始终比较区分大小写,请保留如下方法:下一个代码:
产生这个结果:
Windows 中的默认排序,尤其是 .NET 中的默认排序总是令人惊讶。
我在 en.so 上问过类似的问题。
引用文档(为了便于阅读,我稍微调整了一下):
因此,在排序时,您必须始终指定所需的方法。