以下代码
#!/usr/bin/perl
use strict;
use warnings;
my $s1 = 'aaa2000@yahoo.com';
my $s2 = 'aaa_2000@yahoo.com';
my $s3 = 'aaa2000';
my $s4 = 'aaa_2000';
no locale;
print "\nNO Locale:\n\n";
if ($s1 gt $s2) {print "$s1 is > $s2\n";}
if ($s1 lt $s2) {print "$s1 is < $s2\n";}
if ($s1 eq $s2) {print "$s1 is = $s2\n";}
if ($s3 gt $s4) {print "$s3 is > $s4\n";}
if ($s3 lt $s4) {print "$s3 is < $s4\n";}
if ($s3 eq $s4) {print "$s3 is = $s4\n";}
use locale;
print "\nWith 'use locale;':\n\n";
if ($s1 gt $s2) {print "$s1 is > $s2\n";}
if ($s1 lt $s2) {print "$s1 is < $s2\n";}
if ($s1 eq $s2) {print "$s1 is = $s2\n";}
if ($s3 gt $s4) {print "$s3 is > $s4\n";}
if ($s3 lt $s4) {print "$s3 is < $s4\n";}
if ($s3 eq $s4) {print "$s3 is = $s4\n";}
打印出来
NO Locale:
aaa2000@yahoo.com is < aaa_2000@yahoo.com
aaa2000 is < aaa_2000
With 'use locale;':
aaa2000@yahoo.com is > aaa_2000@yahoo.com
aaa2000 is < aaa_2000
我无法真正遵循:在同一时间,在使用区域设置下,有一个&lt; b AND a@yahoo.com&gt; b@yahoo.com?!!
我错过了一些或多或少的东西,或者这是一个错误?其他人可以确认看到同样的行为吗?
Locale is $ locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
提前致谢。
答案 0 :(得分:4)
启用区域设置后,将在多次传递中完成整理。每个角色都有四个权重,在连续的传球中进行比较。与大多数标点符号一样,@
和_
符号没有主要,次要或三级权重,因此它们仅在第四次传递中发挥作用。所以,对于你的例子
aaa2000@yahoo.com > aaa_2000@yahoo.com
在第一遍中,它真的在比较
aaa2000yahoocom = aaa2000yahoocom
然后在第四次通过(第二次和第三次通过中没有区别因素)
@. > _@.
因为@
恰好大于此区域设置中的_
。 (这只是区域设置定义的选择,可能基于某些ISO标准或其他。)
您可以查看此实现细节。启用了区域设置的比较最终在C库中实现为strxfrm(A) cmp strxfrm(B)
。运行此程序:
use POSIX;
my $s1 = 'aaa2000@yahoo.com';
my $s2 = 'aaa_2000@yahoo.com';
foreach ($s1, $s2) {
printf "%s =>\t%v02x\n", $_, POSIX::strxfrm($_);
}
我明白了:
aaa2000@yahoo.com => 0c.0c.0c.04.02.02.02.24.0c.13.1a.1a.0e.1a.18.01.08.08.08.08.08.08.08.08.08.08.08.08.08.08.08.01.02.02.02.02.02.02.02.02.02.02.02.02.02.02.02.01.08.5d.06.44
# explanation: a a a 2 0 0 0 y a h o o c o m DIV secondary weights ... DIV tertiary weights ... DIV @ .
aaa_2000@yahoo.com => 0c.0c.0c.04.02.02.02.24.0c.13.1a.1a.0e.1a.18.01.08.08.08.08.08.08.08.08.08.08.08.08.08.08.08.01.02.02.02.02.02.02.02.02.02.02.02.02.02.02.02.01.04.36.05.5d.06.44
# explanation: a a a 2 0 0 0 y a h o o c o m DIV secondary weights ... DIV tertiary weights ... DIV _ @ .
这些数字的推导方式是实现细节;它们必须出来,以便字节比较产生所需的最终结果。但是,所有具有区域设置功能的排序的现代编程环境中的概念都是相同的。
答案 1 :(得分:2)
我在使用en_US.utf8
语言环境的32位Linux系统上获得了相同的结果。它不是一个Perl bug,正如这个C程序所示:
#include <locale.h>
#include <string.h>
#include <stdio.h>
void transformed(const char* str)
{
char dest[256];
const char* c;
strxfrm(dest, str, sizeof(dest));
printf("%18s =", str);
for (c = dest; *c; ++c) printf(" %02x", *c);
puts("");
} /* end transformed */
void test_strings(const char* s1, const char* s2)
{
int c = strcoll(s1, s2);
printf("%s is %s %s\n", s1, ((c < 0) ? "<" : ((c == 0) ? "=" : ">")), s2);
} /* end test_strings */
int main(int argc, char* argv[])
{
puts("with C locale:");
test_strings("aaa2000@yahoo.com", "aaa_2000@yahoo.com");
test_strings("aaa2000", "aaa_2000");
setlocale(LC_ALL, "");
puts("\nwith your locale:");
test_strings("aaa2000@yahoo.com", "aaa_2000@yahoo.com");
test_strings("aaa2000", "aaa_2000");
puts("");
transformed("aaa2000@yahoo.com");
transformed("aaa_2000@yahoo.com");
transformed("aaa2000");
transformed("aaa_2000");
return 0;
} /* end main */
使用LANG=en_US.utf8
,它会生成:
with C locale:
aaa2000@yahoo.com is < aaa_2000@yahoo.com
aaa2000 is < aaa_2000
with your locale:
aaa2000@yahoo.com is > aaa_2000@yahoo.com
aaa2000 is < aaa_2000
aaa2000@yahoo.com = 0c 0c 0c 04 02 02 02 24 0c 13 1a 1a 0e 1a 18 01 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 01 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 01 08 5d 06 44
aaa_2000@yahoo.com = 0c 0c 0c 04 02 02 02 24 0c 13 1a 1a 0e 1a 18 01 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 01 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 01 04 36 05 5d 06 44
aaa2000 = 0c 0c 0c 04 02 02 02 01 08 08 08 08 08 08 08 01 02 02 02 02 02 02 02
aaa_2000 = 0c 0c 0c 04 02 02 02 01 08 08 08 08 08 08 08 01 02 02 02 02 02 02 02 01 04 36
strxfrm
函数(您可以通过POSIX模块在Perl中访问)返回一个表示整理顺序的字符串。当你逐个字节地比较两个这样的变换字符串时,第一个具有较小字节的字节在整理顺序中排在第一位。
我不确定这是不是一个bug。我似乎无法找到有关en_US整理顺序如何工作的任何文档。如果 是一个错误,它就在你的C库或语言环境数据库中。