首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用带有文化意识的字母对字符串进行分组

用带有文化意识的字母对字符串进行分组
EN

Stack Overflow用户
提问于 2011-03-31 21:30:14
回答 2查看 141关注 0票数 3

我试图按字符串的初始字母对排序列表进行分组。让我们假设这就是清单:

代码语言:javascript
复制
azaroth 
älgkebab 
orgel 
ölkorv

当根据sv-SE对列表进行排序时,这是排序顺序:

代码语言:javascript
复制
azaroth 
orgel 
älgkebab 
ölkorv

这意味着按首字母分组将是

代码语言:javascript
复制
A
  azaroth
O
  orgel
Ä
  älgkebab
Ö 
  ölkorv

这是有道理的,这也是你在一个使用sv-SE的国家的电话簿中发现的。

当根据en-US对列表进行排序时,这是排序顺序:

代码语言:javascript
复制
älgkebab 
azaroth 
ölkorv
orgel 

现在来了有趣的部分。这意味着按首字母分组将是

代码语言:javascript
复制
AÄ
  älgkebab
  azaroth
OÖ
  ölkorv
  orgel

因为就所有实际目的而言,"a“和”a“在这类中被视为相同的字母,"o”和“o”也是如此,这意味着它们在这方面是相同的首字母。这是AFAIK,你可以在一个使用en-US的国家的电话簿中找到它。

我的问题是,当这种分组因文化而异时,如何通过编程实现它?,或者换句话说,在对特定文化中的列表进行排序时,您如何知道哪些字母被视为“相同”?

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

我有一个可行的解决方案,就是这样做的:

代码语言:javascript
复制
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)

问题是,我不知道它是否适用于任何区域性,甚至不知道SortKeySortKey数组中的第二条数据实际上是什么。MSDN上的页面相当模糊,而且可能是故意的。所以我宁愿有一个更可靠的解决方案。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-03-31 23:32:37

当您比较aäsv-SE中时,结果是-1,所以如果两个单词是相同的,除了umlaut,它们的排序总是相同的。但是,您仍然可以发现它们的排序是相同的:在其中一个和另一个中添加一些字符,对另一个字符进行不同的排序,并对它们进行比较。然后切换添加的字符,然后再进行比较。如果结果不同,则字符排序相同。

示例:

代码语言:javascript
复制
sv-SE:
"a0" < "ä1"
"a1" < "ä0"
en-US:
"a0" < "ä1"
"a1" > "ä0"

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

此外,代码使用01作为附加字符。如果有一些文化中这些字符不影响这类,它将不起作用。

代码语言:javascript
复制
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或空字符串。

票数 1
EN

Stack Overflow用户

发布于 2011-03-31 22:17:34

它可能是一个实现--内部值,类似常量。该值本身并不重要,只是它与其他相关值的比较方式。

这类似于(例如) C中的EOF值,而GCC将其定义为-1,实际值可能会有所不同,因此最终开发人员代码应该只对值进行比较,而不对其进行计算。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5506589

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档