.net - 通过具有文化意识的首字母对字符串进行分组

标签 .net sorting globalization cultureinfo string-comparison

我正在尝试按首字母对字符串进行排序。假设这是列表:

azaroth 
älgkebab 
orgel 
ölkorv

当列表根据sv-SE排序时,这是排序顺序:
azaroth 
orgel 
älgkebab 
ölkorv

这意味着按首字母分组为
A
  azaroth
O
  orgel
Ä
  älgkebab
Ö 
  ölkorv

这很有道理,这也是在使用sv-SE的国家/地区将其分组到电话簿中的方式。

当列表根据en-US排序时,这是排序顺序:
älgkebab 
azaroth 
ölkorv
orgel 

现在来了有趣的部分。这意味着按首字母分组将是
AÄ
  älgkebab
  azaroth
OÖ
  ölkorv
  orgel

由于出于所有实际目的,在排序过程中,“a”和“ä”被视为相同的字母,因此“o”和“ö”也被视为相同的字母,这意味着它们在此目的是相同的首字母。这是AFAIK的用法,您会发现它被分组在使用en-US的国家的电话簿中。

我的问题是,当分组随文化而变化时,如何以编程方式实现此分组? 或者换句话说,当您在特定文化中对列表进行排序时,您如何知道哪些字母被视为“相同”?

例如,我还没有找到一种使StringComparer返回“a”和“ä”的0的方法。

我有一个可行的解决方案,它可以执行以下操作:
if (
    cultureInfo.CompareInfo.GetSortKey("a").KeyData[1] ==
    cultureInfo.CompareInfo.GetSortKey("ä").KeyData[1]
) // same initial (this will return false for sv-SE and true for en-US)

问题是,我不知道它是否适用于任何文化,甚至不知道KeyDataSortKey数组中的第二条数据实际上是什么。 page on MSDN相当模糊,并且可能是故意的。因此,我宁愿有一个更可靠的解决方案。

最佳答案

a中比较äsv-SE时,结果为-1,因此,如果两个单词相同,除了变音符号,它们的排序总是相同的。但是您仍然可以弄清楚它们在其他方面的排序相同:将一个字符附加到其中一个,然后将另一个附加不同的字符,然后进行比较。然后切换添加的字符,然后再次进行比较。如果结果不同,则字符排序相同。

例:

sv-SE:
"a0" < "ä1"
"a1" < "ä0"
en-US:
"a0" < "ä1"
"a1" > "ä0"

因此,在sv-SE中为'a' < 'ä',但在en-US中为'a' == 'ä'。下面是一个根据这些规则对字符串列表进行分组的类。但是对于某些文化,它的排序顺序更为复杂,因此无法正常工作。例如,在捷克语中,ch被视为一个单独的字母,在h之后排序。我不知道你怎么解决。

另外,该代码使用01作为要附加的字符。如果在某些文化中这些字符不会影响排序,那将是行不通的。
class Grouper
{
    StringComparer m_comparer;

    public Grouper(StringComparer comparer)
    {
        m_comparer = comparer;
    }

    public List<Tuple<string, List<string>>> Group(IEnumerable<string> strings)
    {
        List<Tuple<string, List<string>>> result =
            new List<Tuple<string, List<string>>>();

        var sorted = strings.OrderBy(s => s, m_comparer);

        string previous = null;

        List<char> currentGroupName = null;
        List<string> currentGroup = null;

        foreach (var s in sorted)
        {
            char sInitial = ToUpper(s[0]);
            if (currentGroup == null || !AreEqual(s[0], previous[0]))
            {
                if (currentGroup != null)
                    result.Add(Tuple.Create(
                        SortGroupName(currentGroupName),
                        currentGroup));
                currentGroupName = new List<char> { sInitial };
                currentGroup = new List<string> { s };
            }
            else
            {
                if (!currentGroupName.Contains(sInitial))
                    currentGroupName.Add(sInitial);
                currentGroup.Add(s);
            }

            previous = s;
        }

        if (currentGroup != null)
            result.Add(Tuple.Create(SortGroupName(currentGroupName), currentGroup));

        return result;
    }

    string SortGroupName(List<char> chars)
    {
        return new string(chars.OrderBy(c => c.ToString(), m_comparer).ToArray());
    }

    bool AreEqual(char c1, char c2)
    {
        return Math.Sign(m_comparer.Compare(c1 + "0", c2 + "1")) ==
            -Math.Sign(m_comparer.Compare(c1 + "1", c2 + "0"));
    }

    char ToUpper(char c)
    {
        return c.ToString().ToUpper()[0];
    }
}

同样,此类也不符合生产质量,例如,它不处理null或空字符串。

关于.net - 通过具有文化意识的首字母对字符串进行分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5506589/

相关文章:

.net - 我们应该切换到默认使用异步 I/O 吗?

.net - NuGet CLI 抛出错误无法找到 .nupkg

c# - 了解 Windows Universal App (UWP) 中的扩展执行 session

arrays - Swift:用于排序路径的排序函数(需要快!)

.net - 如何识别GC Finalizer线程?

c++ - 如何仅根据第二个字符串对字符串 vector 的 vector 进行排序

python - 当目录很大时用Python列出目录中的文件

javascript - 如何使用 Globalizejs 验证 ICU 消息语法?

.net - .NET:InvariantCulture和en-US之间有什么区别吗?

c# - 为 ASP.NET MVC 错误设置不同的语言