12

我试着理解他们两个,但我没有发现任何差异,除了strcoll() 这个参考说它

根据 LC_COLLATE 类别定义的当前语言环境比较两个以空字符结尾的字符串。

第二个想法,我知道我在问另一个问题以获得详细答案,对于 C 和 C++,这个语言环境到底是什么?

4

2 回答 2

31

strcmp()一个接一个地获取字符串的字节并将它们与字节进行比较。

strcoll()获取字节,使用语言环境转换它们,然后比较结果。转换根据语言重新排序。在法语中,重音字母在非重音字母之后。所以ée之后。但是,éf之前。strcoll()做对了。strcmp()不太好。

但是,在许多情况下strcmp()就足够了,因为您不需要显示以使用的语言(区域设置)排序的结果。例如,如果您只需要快速访问由字符串索引的大量数据,您将使用由该字符串索引的地图。strcoll()对那些通常非常慢的使用进行排序可能完全没用(strcmp()至少与此相比。)

有关字符的详细信息,您可能还需要查看Unicode网站。

关于语言环境,它是语言。默认情况下,它设置为“C”(或多或少,没有语言环境)。选择位置后,将相应地设置区域设置。您还可以设置 LC_LOCALE 环境变量。实际上有很多这样的变数。但一般来说,您使用预定义的函数会自动考虑这些变量并为您做正确的事情。(即格式化日期/时间、格式化数字/度量、计算大写/小写等)

于 2012-12-30T00:14:30.523 回答
3

由于某种原因,在我测试的所有 unicode 语言环境中,在几个不同版本的 glibc 上,strcoll() 对任何两个平假名都返回零。这会破坏sortuniq以及以某种方式与字符串顺序交互的所有内容。

$ echo -e -n 'い\nろ\nは\nに\nほ\nへ\nと\n' | 排序 | 独特的

い</p>

这简直是​​坏了,无法修复。世界不同地方的人可能对“い”应该放在“ろ”之前还是之后有不同的想法,但没有理智的人会认为它们是相同的。

不,将您的语言环境设置为日语并不重要:

$ LC_ALL=ja_JP.utf8 LANG=ja_JP.utf8 LC_COLLATE=ja_JP.utf8 echo -e -n 'い\nろ\nは\nに\nほ\nへ\nと\n' | 排序 | 独特的

い</p>

There was discussion in some official mailing list, but guess what, it was in 2002 and it was never fixed because people don't care: https://www.mail-archive.com/linux-utf8@nl.linux.org/msg02658.html

That bug happened to us in some day and in the end our only way out was to set the collate locale to "C" and rely on the nice properties of utf-8 encoding. That's a horrible experience, since one shouldn't really work under "C" locale when processing all-Japanese data.

So for your sanity's sake, do NOT directly use strcoll. A safer variant might be:

int safe_strcoll(const char *a, const char *b)
{
  int ret = strcoll(a, b);
  if (ret != 0) return ret;
  return strcmp(a, b);
}

just in case strcoll() decides to screw you...

EDIT: I just repeated the experiment out of curiosity, and my current system (with glibc 2.29) works without problems now. Locale doesn't matter either.

于 2016-07-31T14:05:47.743 回答