【问题标题】:Perl Unicode test on OS X fails on DebianOS X 上的 Perl Unicode 测试在 Debian 上失败
【发布时间】:2013-09-20 14:04:06
【问题描述】:

我有以下测试:

use Test::More;
use Lingua::EN::NameCase 'nc';
use utf8;
my $output = Test::Builder->new->todo_output;
binmode $output, ':encoding(UTF-8)';
$output = Test::Builder->new->failure_output;
binmode $output, ':encoding(UTF-8)';

my $name = 'Lintão';
is nc($name), $name, 'nc() should not change a properly namecased name';
diag nc($name);

done_testing;

在带有 Perl 5.10.1 的 Mac OS X 上,我得到以下输出:

nc.t ..
ok 1 - nc() should not change a properly namecased name
1..1
# Lintão
ok
All tests successful.
Files=1, Tests=1,  0 wallclock secs ( 0.02 usr  0.01 sys +  0.04 cusr  0.00 csys =  0.07 CPU)
Result: PASS

不幸的是,在 Debian Squeezebox 上使用 5.10.1 Perl 进行的相同测试会产生以下输出:

nc.t ..
not ok 1 - nc() should not change a properly namecased name

#   Failed test 'nc() should not change a properly namecased name'
#   at nc.t line 10.
#          got: 'LintãO'
#     expected: 'Lintão'
# LintãO
1..1
# Looks like you failed 1 test of 1.
Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/1 subtests

Test Summary Report
-------------------
nc.t (Wstat: 256 Tests: 1 Failed: 1)
  Failed test:  1
  Non-zero exit status: 1
Files=1, Tests=1,  0 wallclock secs ( 0.01 usr  0.00 sys +  0.03 cusr  0.00 csys =  0.04 CPU)
Result: FAIL

nc() 子例程中的违规行似乎是这样的:

s{ \b (\w)   }{\u$1}gox ;           # Uppercase first letter of every word.

所以不知何故,Debian 上相同版本的 Perl 错误地理解了边界一词。谁能帮我进一步调试?

【问题讨论】:

  • 我运行的不是 Squeeze,而是一个 Ubuntu。可以使用带有 L::EN::NC v1.15 的 perl 5.18.1 重现。
  • 有趣的一点我还无法理解:如果我们将字符串分解为 NFD 或 NFKD,一切都会正常工作。只有 NFC 和 NFKC 才会出现故障。

标签: perl unicode


【解决方案1】:

Linux 机器上的语言环境不将 ã 视为单词字符(Lingua::EN::NameCase 具有 use locale;,因此它使用当前的 LC_CTYPE 设置进行字符分类)。 perlbrewed perls 的范围从 5.8.1 到 5.18.1,我在 Ubuntu 12.04 LTS 上使用en_GB.UTF-8 语言环境得到这个输出:

$ perl -Mutf8 -le 'print 0+("ã" =~ /\w/); use locale; print 0+("ã" =~ /\w/)'
1
0

【讨论】:

  • 啊,现在我明白了。 ã 被编码为\xE3,这是一个单字节。因此,适用区域设置规则。通过在字符串中引入多字节字符,我们可以强制使用 unicode 语义,如 perldoc perlre 中所述。这些规则非常复杂。
  • 不,单/多字节不会进入其中,只有use locale; 和语言环境对单词字符的概念。我已经编辑了响应来证明这一点。
  • 那么,我仍然不确定修复方法。我尝试在 BEGIN 块中设置 LC_CTYPE='UTF-8' ,但我仍然遇到同样的失败。缺少猴子补丁 Lingua::EN::NameCase,我该如何解决?
  • LC_CTYPE 接受<language>_<country>.<encoding>,而不仅仅是编码(因为不同的语言对字符分类有不同的想法) 在 BEGIN {} 块中设置环境变量为时已晚,因为它是由 libc 设置的在启动时。您需要setlocale(),但这可能也无济于事,因为Linux en_GB.UTF-8 语言环境不认为'ã' 是一个单词字符。我会修补 Lingua::EN::NameCase 以选择使用 Unicode 而不是语言环境定义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-11-28
  • 2016-01-21
  • 1970-01-01
  • 2021-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多