使用排序规则对数组进行排序

8
我有一个用法语单词构成的数组:['États-Unis','Espagne'等],我希望按照其所属区域(fr_FR)的字母顺序进行排序。
我使用以下代码:
$collator = new Collator('fr-FR');
echo $collator->getErrorMessage();
$collator->asort($array);

但是我收到一个U_USING_DEFAULT_WARNING错误,我认为默认使用英语或其他语言环境。更重要的是,数组没有正确排序(美国出现在西班牙之前,我希望相反的情况发生)。我已经安装了intl软件包,并且我的系统有对应的语言环境(Ubuntu)。
$locale -a
C
C.UTF-8
en_US.utf8
es_ES.utf8
fr_FR
fr_FR.iso88591
fr_FR.utf8
POSIX

我尝试了不同的组合来构建排序对象,但并没有好的结果:"fr-FR"、"fr-FR.UTF8"等等。
还有其他我需要注意的地方吗?

嗯,你试过使用 fr_FR 了吗? - eis
是的,我也尝试了那个,但没有用。顺便说一下,我之前并没有设置任何语言环境,只是使用这个Collator类。我认为不需要设置语言环境才能工作,对吗? - Dan
不应该。您可以测试一下collator_create()是否会有任何区别,或者检查Collator::FRENCH_COLLATION - eis
是的,我最后做的事情是改用Collator :: create()并获得了相同的结果。 - Dan
3个回答

6
根据这篇博客文章,对于单词cotecotécôtecôté(已按英语排序),在法语中的排序顺序为:cotecôtecotécôté。以下代码按照法语排序规则对这些单词进行排序:
$words = array('cote', 'coté', 'côte',  'côté');
print_r($words);

$collator = new Collator('fr_FR');

// print info about locale
echo 'French Collation ' . (($collator->getAttribute(Collator::FRENCH_COLLATION) ==    Collator::ON) ? 'On' : 'Off') . "\n";
echo $collator->getLocale(Locale::VALID_LOCALE) . "\n";
echo $collator->getLocale(Locale::ACTUAL_LOCALE) . "\n";

$collator->asort($words);

print_r($words);

打印的结果如下:

Array
(
    [0] => cote
    [1] => coté
    [2] => côte
    [3] => côté
)
French Collation On
fr_FR
fr
Array
(
    [0] => cote
    [2] => côte
    [1] => coté
    [3] => côté
)

在同一篇博客文章中,作者说:
[...] 重音符号是从右到左进行评估,而不是从左到右。因此,côte排在coté之前,而不是像英语等从左到右的语言中那样排在其后。因为单词côte在末尾的字母“e”上没有锐音符号,而coté有。在英语和大多数其他语言中,评估从左侧开始,因此“o”上的脱字符或缺失是排序的控制因素。
因此,如果您有一个包含单词Spain和US的数组,则它们在英语和法语中的顺序相同。
您还应该注意,asort方法保持数组的索引关联。看看它们之间的区别:
asort:
Array
(
    [0] => cote
    [2] => côte
    [1] => coté
    [3] => côté
)

sort:
Array
(
    [0] => cote
    [1] => côte
    [2] => coté
    [3] => côté
)

关于U_USING_DEFAULT_WARNING

根据这个 API 文档

U_USING_DEFAULT_WARNING 表示使用了默认的区域设置数据;未找到请求的区域设置或其任何回退区域设置。

例如,当我使用 fr_FR 区域设置时,会收到 U_USING_FALLBACK_WARNING,这表示使用了回退区域设置,在本例中是区域设置 fr

区域设置

似乎您的计算机没有支持法语语言(或者虽然命令 locale -a 显示了法语包,但 PHP 无法使用它然后回退到默认语言),我有一些建议可以尝试。

首先,列出所有支持的区域设置:

cat /usr/share/i18n/SUPPORTED 

现在,生成您所需的语言:
sudo locale-gen fr_FR.UTF-8
sudo locale-gen fr_FR.ISO-8859-1
sudo dpkg-reconfigure locales

如果不起作用,请尝试安装包language-pack-frlanguage-support-fr,然后再次生成语言。
这个问题很奇怪。我有一个Ubuntu 11.04的VM,PHP 5.3.8也正常运行,在我的Debian 6上也是如此,而我没有安装任何软件包或配置任何东西。

谢谢你的回答。我刚刚在我的系统上尝试了你的示例,但实际上我遇到的问题是我似乎无法实例化法语排序器。当我尝试你的代码时,我得到了:"French Collation Off, fr_FR, root",即使我碰巧在我的系统中有法语区域设置(请参见原始帖子)。你知道这可能是什么原因吗? - Dan
抱歉回复晚了。我最终通过完全重新安装解决了问题。我找不出是什么导致我无法使用本地化设置。感谢您详尽的回复。 - Dan

0

我正在使用Cygwin:

$ locale -a | grep fr_FR
fr_FR
fr_FR.utf8
fr_FR@euro

(注意输出中没有fr_FR.iso88591

代码(文件编码为UTF-8):

$collator = new Collator('fr_FR');
var_dump($collator->getErrorMessage());

// FRENCH_COLLATION is OFF

$arr = array('États-Unis', 'Espagne');

var_dump($collator->getAttribute(Collator::FRENCH_COLLATION) == Collator::ON);
var_dump($collator->getLocale(Locale::VALID_LOCALE));
var_dump($collator->getLocale(Locale::ACTUAL_LOCALE));
$collator->asort($arr);
var_dump($arr);

// FRENCH_COLLATION is ON

$collator->setAttribute(Collator::FRENCH_COLLATION, Collator::ON);

$arr = array('États-Unis', 'Espagne');

var_dump($collator->getAttribute(Collator::FRENCH_COLLATION) == Collator::ON);
var_dump($collator->getLocale(Locale::VALID_LOCALE));
var_dump($collator->getLocale(Locale::ACTUAL_LOCALE));
$collator->asort($arr);
var_dump($arr);

输出:

string(23) "U_USING_DEFAULT_WARNING"
bool(false)
string(5) "fr_FR"
string(4) "root"
array(2) {
  [1]=>
  string(7) "Espagne"
  [0]=>
  string(11) "États-Unis"
}
bool(true)
string(5) "fr_FR"
string(4) "root"
array(2) {
  [1]=>
  string(7) "Espagne"
  [0]=>
  string(11) "États-Unis"
}

这里的诀窍是:我将文件编码转换为ISO 8859-1(在vim中,我执行:set fileencoding=iso-8859-1),然后再试一次:

string(23) "U_USING_DEFAULT_WARNING"
bool(false)
string(5) "fr_FR"
string(4) "root"
array(2) {
  [0]=>
  string(10) "▒tats-Unis"
  [1]=>
  string(7) "Espagne"
}
bool(true)
string(5) "fr_FR"
string(4) "root"
array(2) {
  [0]=>
  string(10) "▒tats-Unis"
  [1]=>
  string(7) "Espagne"
}

有些符号是损坏的,但我认为这是因为我的终端不支持给定的代码页。主要问题是字符串的顺序现在正是你所描述的:“Espagne”在“États-Unis”之后。

所以,我认为这是一个文件编码的问题。


0

试试只写‘FR’,我猜应该可以在你的系统上运行:

$collator = new Collator('FR');

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