RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 655666
Accepted
dm.dymov
dm.dymov
Asked:2020-04-19 20:01:46 +0000 UTC2020-04-19 20:01:46 +0000 UTC 2020-04-19 20:01:46 +0000 UTC

对包含字母 Y 的俄语字符和字符串数组进行排序

  • 772

一个简单的代码示例,让我们尝试对俄语字符数组进行排序:

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和ё用于一个字符,而不是实施公平排序?是某人的任性决定还是仍然在某些规范中定义?

我了解并非所有问题都意味着社区普通成员的明确回答,但我在此提及。

或者也许我误解了一切,如果是这样的话请纠正我。

谢谢你。

c#
  • 3 3 个回答
  • 10 Views

3 个回答

  • Voted
  1. Best Answer
    VladD
    2020-04-20T04:33:00Z2020-04-20T04:33:00Z

    在这里,让你惊讶的不是BCL算法的奇怪,而是Unicode标准的实现。

    Unicode® Technical Standard #10 / Unicode Collat​​ion Algorithm文档指出(我的翻译):

    1.1 多层次比较

    人类语言所需要的排序是复杂的。为了正确实现它,使用了多级比较算法。

    比较两个单词时,基本字母是最重要的,例如,I 和 E 之间的区别。如果基本字母不匹配,通常会忽略重音。如果基本字母或其重音不同,通常也会忽略大小写差异(大写/小写) 。

    标点符号如何处理取决于具体情况。在某些情况下,点或逗号被视为单独的基本字母。在其他情况下,如果基本字母、重音或大小写已经存在差异,则标点符号将被忽略。

    在相等的情况下,有时会进行最终比较:如果没有其他差异,则比较(规范化的)代码点。

    于是,词的比较进行如下:

    1. 大小写区别和重音被丢弃。如果比较确定了哪个词更大,则算法结束。
    2. 返回重音,重复比较。如果比较确定了哪个词更大,则算法结束。
    3. 返回寄存器,重复比较。如果比较确定了哪个词更大,则算法结束。

    和。等等

    对于俄语,根据“填字游戏原则”,Yo被认为是E的重音变体,Y是I的重音变体。

    我希望在 Unicode 中选择俄语标准能够得到语言学家的同意。

    如何在 .NET 中更改它 - 如何强制E被视为位于E和F之间的单独字母,我不会马上说。(但请参阅相邻的答案。)


    顺便说一下,一个或另一个 Unicode 标准的实现不是语言的特性,而是系统的特性。BCL 要求系统比较字符串,以免复制 Unicode 实现。这意味着相同的程序,当安装在 Windows 7 和 Windows 10 上时,在排序方面可能会有不同的行为。


    澄清

    对于俄语语言环境, Y被认为是AND的单独字母,而对于英语,Y被认为是AND的重音版本。There 和 There的字母Yo都被认为是 E 的重音版本。例子:

    var strings = new[] { "Иа", "Йокогама", "Италия", "Ель", "Ёлочка" };
    var en = CultureInfo.GetCultureInfo("en-US");
    var ru = CultureInfo.GetCultureInfo("ru-RU");
    var orderEn = strings.OrderBy(s => s, StringComparer.Create(en, false));
    Console.WriteLine("en-US: " + string.Join(" ", orderEn));
    var orderRu = strings.OrderBy(s => s, StringComparer.Create(ru, false));
    Console.WriteLine("ru-RU: " + string.Join(" ", orderRu));
    

    产生这个结果:

    en-US: Ёлочка Ель Иа Йокогама Италия
    ru-RU: Ёлочка Ель Иа Италия Йокогама
    

    故事的寓意:对字符串进行排序时,请始终指定语言环境!

    • 6
  2. Андрей NOP
    2020-04-20T12:34:01Z2020-04-20T12:34:01Z

    除了@VladD 的回答:

    如何在 .NET 中更改它 - 如何将 E 作为位于 E 和 F 之间的单独字母,我不知道。

    或者,您可以实现自己的IComparer,例如:

    class MyStringComparer : IComparer<string>
    {
        int IComparer<string>.Compare(string x, string y)
        {
            int result = CompareAlgorithm(x.ToLowerInvariant(), y.ToLowerInvariant());
            if (result != 0) return result;
            return CompareAlgorithm(x, y);
        }
    
        static readonly string symbols = " абвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ.,:";
    
        int CompareAlgorithm(string x, string y)
        {
            int i = 0, j = 0;
            while(x.Length > i && y.Length > j)
            {
                int indexX = symbols.IndexOf(x[i]);
                int indexY = symbols.IndexOf(y[i]);
                if (indexX == -1)
                {
                    ++i;
                    continue;
                }
                if (indexY == -1)
                {
                    ++j;
                    continue;
                }
                if (indexX < indexY) return -1;
                if (indexX > indexY) return 1;
                ++i;
                ++j;
            }
            if (x.Length <= i && y.Length <= j) return 0;
            if (x.Length <= i) return -1;
            else return 1;
        }
    }
    

    字符串比较是逐个字符进行的,比较中涉及的字符在 中指定symbols,按所需的升序排列,不在的字符将symbols被忽略。

    在方法本身Compare中,我们首先进行不区分大小写的比较,如果产生相同的结果,我们进行区分大小写的比较。这种行为是可以改变的。如果您想始终比较区分大小写,请保留如下方法:

    int IComparer<string>.Compare(string x, string y)
    {
        return CompareAlgorithm(x, y);
    }
    

    下一个代码:

    var a = new string[]
    {
        "жар",
        "дом",
        "ель",
        "ёлка",
        "домовой",
        "д.ом",
        "д-ом",
        "ДОм"
    };
    
    var b = a.OrderBy(x => x, new MyStringComparer()).ToList();
    Console.WriteLine(string.Join(" ", b));
    

    产生这个结果:

    д-ом дом ДОм домовой д.ом ель ёлка жар
    
    • 3
  3. Alexander Petrov
    2020-04-19T20:44:55Z2020-04-19T20:44:55Z

    Windows 中的默认排序,尤其是 .NET 中的默认排序总是令人惊讶。

    我在 en.so 上问过类似的问题。

    引用文档(为了便于阅读,我稍微调整了一下):

    .NET Framework 使用三种不同的排序方法:按单词、按字符串和按序号。

    因此,在排序时,您必须始终指定所需的方法。

    • 2

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    Python 3.6 - 安装 MySQL (Windows)

    • 1 个回答
  • Marko Smith

    C++ 编写程序“计算单个岛屿”。填充一个二维数组 12x12 0 和 1

    • 2 个回答
  • Marko Smith

    返回指针的函数

    • 1 个回答
  • Marko Smith

    我使用 django 管理面板添加图像,但它没有显示

    • 1 个回答
  • Marko Smith

    这些条目是什么意思,它们的完整等效项是什么样的

    • 2 个回答
  • Marko Smith

    浏览器仍然缓存文件数据

    • 1 个回答
  • Marko Smith

    在 Excel VBA 中激活工作表的问题

    • 3 个回答
  • Marko Smith

    为什么内置类型中包含复数而小数不包含?

    • 2 个回答
  • Marko Smith

    获得唯一途径

    • 3 个回答
  • Marko Smith

    告诉我一个像幻灯片一样创建滚动的库

    • 1 个回答
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Алексей Шиманский 如何以及通过什么方式来查找 Javascript 代码中的错误? 2020-08-03 00:21:37 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    user207618 Codegolf——组合选择算法的实现 2020-10-23 18:46:29 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5