Perl Unicode内部 - 乱用utf8

时间:2012-05-30 21:14:22

标签: perl unicode utf-8

在任何人告诉我RTFM之前,我必须说 - 我已经深入了解:

所以,基本代码:

use 5.014;           #getting 'unicode_strings' feature
use uni::perl;       #turning on many utf8 things
use Unicode::Normalize  qw(NFD NFC);
use warnings;
while(<>) {
    chomp;
    my $data = NFD($_);
    say "OK" if utf8::is_utf8($data);
}

此时,来自 utf8 编码的STDIN我在$data中得到了一个正确的 unicode 字符串,例如“\ w”将匹配多字节[\p{Alphabetic}\p{Decimal_Number}\p{Letter_Number}](可能更多)。那没关系,而且很有效。

AFAIK $data 包含utf8,但是perl's internal Unicode格式的字符串。

现在问题:

  • 我如何确保(测试它),任何$other_data包含有效的Unicode字符串?
  • utf8 :: is_utf8($ data)的目的是什么?整个utf8 pragma对我来说是一个谜。

我理解use utf8;只是为了告诉Perl我的源代码是在utf8中(所以做类似的事情,就像我的脚本以BOM标志开始 - 对于BigEndian) - 从Perl的角度来看,我的源代码就像一个外部文件 - 而Perl应该知道它是什么编码......

在上面的示例中,utf8::is_utf8($data)将打印正常 - 但我不明白为什么。

内部Perl不使用utf8,因此我的utf8数据文件被转换为Perl的内部Unicode,为什么utf8::is_utf8($data)$data返回true,而不是以utf8格式?或者它被错误命名,该函数应命名为uni :: is_unicode($ data)???

提前感谢您的澄清。

Ps:@brian d foy - 是的,我还没有 Effective Perl Programming 书 - 我会得到它 - 我保证:) /开玩笑/

2 个答案:

答案 0 :(得分:7)

is_utf8返回有关使用了哪种内部存储格式的信息,周期。

  • 它与字符串的值无关(尽管某些字符串只能以两种格式之一存储)。
  • 与字符串是否已被解码无关。
  • 与字符串是否包含使用UTF-8编码的内容无关。
  • 这不是任何形式的有效性检查。

现在回答你的问题。


整个utf8编译指示对我来说是一个谜。

use utf8;告诉perl您的源代码是使用UTF-8编码的。如果你不这么说,perl有效地假定它是iso-8859-1(作为内部机制的副作用)。

utf8 :: namespace中的函数与pragma无关,它们有多种用途。

  • utf8::encodeutf8::decode:有用的编码和解码功能。与Encode的encode_utf8decode_utf8类似,但它们可以就地生效。
  • utf8::upgradeutf8::downgrade:很少使用,但对于解决XS模块中的错误非常有用。更多内容如下。
  • utf8::is_utf8:我不知道为什么会有人使用它。

我如何确保(测试它),比任何$ other_data包含有效的unicode字符串?

&#34;有效的Unicode字符串&#34;对你意味着什么? Unicode对于不同的情况有不同的有效定义。


出于什么目的是utf8 :: is_utf8($ data)?

调试。它偷看了Perl胆量。


在上面的示例中,utf8 :: is_utf8($ data)将打印正常 - 但不明白为什么。

因为NFD碰巧选择返回包含UTF8 = 1格式字符串的标量。

Perl有两种​​用于存储字符串的格式:

  • UTF8 = 0可以存储一系列8位值。
  • UTF8 = 1可以存储一系列72位值(尽管实际上限制为32位或64位。)

第一种格式使用更少的内存,并且在访问字符串中的特定位置时速度更快,但它可以包含的内容有限。 (例如,它不能存储Unicode代码点,因为它们需要21位。)Perl可以在两者之间自由切换。

use utf8;
use feature qw( say );

my $d = my $u = "abcdé";
utf8::downgrade($d);  # Switch to using the UTF8=0 format for $d.
utf8::upgrade($u);    # Switch to using the UTF8=1 format for $u.

say utf8::is_utf8($d) ?1:0;   # 0
say utf8::is_utf8($u) ?1:0;   # 1
say $d eq $u          ?1:0;   # 1

人们通常不必担心这一点,但有一些错误的模块。尽管有use feature qw( unicode_strings );,但Perl甚至还有错误的角落。可以使用utf8::upgradeutf8::downgrade将标量的格式更改为XS函数所期望的格式。


或者它命名错误,函数应命名为uni :: is_unicode($ data)???

那没有好转。 Perl无法知道字符串是否是Unicode字符串。如果您需要跟踪它,您需要自己跟踪它。

UTF8 = 0格式的字符串可能包含Unicode代码点。

my $s = "abc";  # U+0041,0042,0043

UTF8 = 1格式的字符串可能包含不是Unicode代码点的值。

my $s = pack('W*', @temperature_measurements);

答案 1 :(得分:6)

  

我如何确保(测试它),而不是任何$ other_data包含有效的unicode字符串?

您无法确定事后是否字符串具有字符语义或字节语义。 Perl不会为您跟踪此信息。您必须通过仔细编程来跟踪它:在边界处进行编码和解码; :raw layer用于字节语义,:encoding(foo)用于字符语义。使用naming conventions获取变量和函数,以清楚地区分语义并使错误的代码看起来错误。

  

出于什么目的,utf8 :: is_utf8($ data)?

它告诉你SvUTF8标志的存在,仅此而已。对于大多数开发人员来说,这几乎完全没用,因为它是一个内部的东西。该标志并不意味着字符串具有字符语义,它的缺失并不意味着字符串具有字节语义。

  

整个utf8 pragma对我来说都是一个谜。

可能是因为它过度记录,因此令人困惑。大多数开发人员可以在声明其目的是在源代码中启用Unicode文字的部分之后停止阅读。

  

在上面的示例中,utf8 :: is_utf8($ data)将打印正常 - 但不明白为什么。

因为uni :: perl启用了use open qw(:utf8 :std);。从STDIN读取的任何带有<>的输入都将被解码。之后的归一化步骤不会改变它。