C#比较带有变音符号的字符串产生奇怪结果

3
我使用 string.Compare(strA, strB, true, CultureInfo.CurrentCulture);,但不理解结果。CurrentCulture 是 "de-DE"。
string.Compare( "o", "ö", true, CultureInfo.CurrentCulture) // result: -1 
string.Compare( "d", "f", true, CultureInfo.CurrentCulture) // result: -1 
string.Compare( "dx", "fa", true, CultureInfo.CurrentCulture) // result: -1 
string.Compare( "ox", "öa", true, CultureInfo.CurrentCulture) // result: 1 
string.Compare( "oa", "öx", true, CultureInfo.CurrentCulture) // result: -1

为什么结果取决于第二个字母,最后两行会得到不同的结果? 如果 o 是第一个,ö 是下一个,那么第4行是否也应该返回 -1 ? 有人能解释一下吗?
为了解释我在这里遇到的问题,我们来比较一些代码:
class Program
    {
        public class ComparerB : IComparer<string>
        {
            public int Compare(string x, string y)
            {
                return string.CompareOrdinal(x, y);
            }
        }

        public class ComparerA : IComparer<string>
        {
            public int Compare(string x, string y)
            {
                return string.Compare(x, y, true, CultureInfo.CurrentCulture);
            }
        }

        static void Main(string[] args)
        {
            List<string> list = new List<string>();
            list.Add("Update");
            list.Add("Ö3 Greatest Hits");
            list.Add("Dont sleep");
            list.Add("Friends");
            list.Add("Dart vadder");
            list.Add("Family");
            list.Add("Oxfort");
            list.Add("Ödipus");
            list.Add("Oasis");
            list.Add("Österreich");
            list.Add("Panda");

            list.Sort(new ComparerA());
            foreach (var item in list)
            {
                Console.WriteLine(item);
            }
            Console.WriteLine();
            list.Sort(new ComparerB());
            foreach (var item in list)
            {
                Console.WriteLine(item);
            }

            Console.ReadLine();
        }
    }

使用 ComparerA 得到的结果为(混合了 Ö 和 O):

Dart vadder
Dont sleep
Family
Friends
Ö3 Greatest Hits
Oasis
Ödipus
Österreich
Oxfort
Panda
Update

使用 ComparerB 得到的结果为(Ö 在列表结尾):

Dart vadder
Dont sleep
Family
Friends
Oasis
Oxfort
Panda
Update
Ö3 Greatest Hits
Ödipus
Österreich

但我需要的是这个(Ö 出现在 O 后):

Dart vadder
Dont sleep
Family
Friends
Oasis
Oxfort
Ö3 Greatest Hits
Ödipus
Österreich
Panda
Update


你期望得到什么?因为我们大多数人不懂德语。 - styx
这是预期的结果:“大于零:strA在排序顺序中跟随strB。”。请参阅String.Compare(String, String, Boolean, CultureInfo)。你是否期望进行相等比较? - Filburt
如果我使用这个来对列表进行排序,我会得到一个混合了O和Ö的结果。如果我使用CompareOrdinal,我会得到结果不混合,但是特殊字符会出现在列表的末尾。我想要得到一个按照顺序排列的列表:首先是所有带有O的,然后是所有带有Ö的。 - Udo
如果您想的话,可以定义自己的 CultureInfo,其中ÖO之前排序。但是在德语中,根据微软和其他公司的实现,它们排序方式不同。您可以进行反向排序,但显然这也会以不同的方式对其他字符进行排序。 - Charlieface
德语字母表中,ÄÖÜ在Z之后排序。因此,“ComparerB”示例似乎可以正常工作。参见:https://en.wikipedia.org/wiki/German_orthography “[Umlauts]被官方认为是字母表中不同的字母。”因此,它们不仅仅是AOU的“特殊种类”。-虽然这并没有真正帮助你。也许有一种方法可以创建自己的“IComparer<string>”,但这可能很快就会变成一个你不想涉足的麻烦事。 - Corak
2个回答

3
在你的比较器 A中,你有以下代码。
return string.Compare(x, y, true, CultureInfo.CurrentCulture);

这意味着您正在使用德语的 CurrentCulture,我想是这样,因此根据我在互联网上注意到的内容,德语字母表的顺序如下:
A、B、C、D、E、F、G、H、I、J、K、L、M、N、O、P、Q、R、S、T、U、V、W、X、Y、Z、Ä、Ö、Ü、ß
所以,排序将相应地进行,我认为你目前得到的是正确的,但如果您仍需要按照您的意愿进行,并且您愿意使用另一个CultureInfo,其中O、Ö的顺序就像土耳其语中那样,直接彼此相接,那么代码应该是这样的:
return string.Compare(x, y, true, new CultureInfo("tr-TR"));

这将为您提供以下结果:
Dart vadder
Dont sleep
Family
Friends
Oasis
Oxfort
Ö3 Greatest Hits
Ödipus
Österreich
Panda
Update

另一种选择是开发您自己的自定义排序算法和函数,该算法和函数考虑您喜欢的任何字符序列。


1
谢谢。使用“tr-TR”我得到了我想要的结果。我已经尝试过“de-DE_phoneb”,但没有任何变化。 - Udo
为此感到开心 :) - Useme Alehosaini

3
我认为在德语字母表中,特殊字符ö内部表示为oe
因此,string.Compare( "o", "ö", true, System.Globalization.CultureInfo.CurrentCulture);等同于string.Compare( "o", "oe", true, System.Globalization.CultureInfo.CurrentCulture);
string.Compare( "ox", "öa", true, System.Globalization.CultureInfo.CurrentCulture);等同于string.Compare( "ox", "oea", true, System.Globalization.CultureInfo.CurrentCulture);。然后结果1是有意义的。

好的,谢谢。但问题是如何对列表进行排序。比较结果是混合了以 o 和 ö 开头的条目。CompareOrdinal 和特殊字符在列表末尾。我需要的是一个所有以 o 开头的条目都在前面,然后是所有以 ö 开头的列表... - Udo
@Udo能否请您更新您的问题,提供输入数据示例和期望的结果,以便更好地理解您的意思?! - Useme Alehosaini
@Useme Alehosaini。我添加了一个例子。 - Udo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接