【问题标题】:Perl: String literal in module in latin1 - I want utf8Perl:latin1 模块中的字符串文字 - 我想要 utf8
【发布时间】:2011-07-14 14:11:07
【问题描述】:

Date::Holidays::DK 模块中,某些丹麦节日的名称以Latin1 编码编写。例如,1 月 1 日是“Nytårsdag”。为了获得正确的 utf8 编码字符串,我应该对下面的 $x 做什么?

use Date::Holidays::DK;
my $x = is_dk_holiday(2011,1,1);

我在use Date::Holidays::DK之前/之后尝试了use utf8no utf8的各种组合,但似乎没有任何效果。我还尝试使用 Encode 的decode,但没有成功。更具体地说,

use Date::Holidays::DK;
use Encode;
use Devel::Peek;
my $x = decode("iso-8859-1", 
           is_dk_holiday(2011,1,1)
          );
Dump($x);
print "January 1st is '$x'\n";

给出输出

SV = PV(0x15eabe8) at 0x1492a10
  REFCNT = 1
  FLAGS = (PADMY,POK,pPOK,UTF8)
  PV = 0x1593710 "Nyt\303\245rsdag"\0 [UTF8 "Nyt\x{e5}rsdag"]
  CUR = 10
  LEN = 16
January 1st is 'Nyt sdag'

(在 t 和 s 之间有一个无效字符)。

【问题讨论】:

    标签: perl encoding utf-8 perl-module latin1


    【解决方案1】:

    在使用Date::Holidays::DK之前/之后使用utf8和no utf8,但它似乎没有任何效果。

    正确。 utf8 pragma 仅表示程序的源代码是用 UTF-8 编写的。

    我也尝试使用Encode的解码,但没有成功。

    你没有正确地理解这一点,你实际上做了正确的事。你现在有一个 Perl 字符的字符串并且可以操作它了。

    t 和 s 之间有一个无效字符

    你也解释错了,其实是å这个字符。


    您想输出 UTF-8,因此缺少编码步骤。

    my $octets = encode 'UTF-8', $x;
    print $octets;
    

    请阅读http://p3rl.org/UNI 了解编码主题的介绍。您始终必须显式或隐式地解码和编码。

    【讨论】:

      【解决方案2】:

      use utf8 只是提示 perl 解释器/编译器您的文件是 UTF-8 编码的。如果您有设置高位的字符串,它会自动将它们编码为 un​​icode。

      如果您有一个以 iso-8859-1 编码的变量,则必须对其进行解码。然后你的变量是内部 unicode 格式。那是 utf8,但你不应该关心 perl 内部使用哪种编码。

      现在,如果您想打印这样的字符串,您需要将 unicode 字符串转换回字节字符串。你需要在这个字符串上做一个encode。如果您不手动进行编码,perl 本身会将其编码回 iso-8859-1。这是默认编码。

      在打印变量 $x 之前,您需要在其上执行 $x = encode('UTF-8', $x)

      为了正确处理 UTF-8,您始终需要通过 I/O 对每个外部输入进行 decode()。而且你总是需要 encode() 离开你的程序的所有东西。

      要更改默认输入/输出编码,您可以使用类似这样的方法。

      use utf8;
      use open ':encoding(UTF-8)';
      use open ':std';
      

      第一行说你的源代码是用 utf8 编码的。第二行说每个输入/输出都应该自动编码为 utf8。需要注意的是,open() 也会以 utf8 模式打开文件。如果您使用二进制文件,则需要在句柄上调用 binmode()

      但第二行不会改变对 STDIN、STDOUT 或 STDERR 的处理。第三行将改变这一点。

      您可能可以使用模块utf8:all 来简化此过程。但是了解这一切在幕后是如何运作的总是好的。

      纠正你的例子。一种可能的方法是:

      #!/usr/bin/env perl
      use Date::Holidays::DK;
      use Encode;
      use Devel::Peek;
      my $x = decode("iso-8859-1", 
                 is_dk_holiday(2011,1,1)
                );
      Dump($x);
      print encode("UTF-8", "January 1st is '$x'\n");
      

      【讨论】:

      • 我希望您删除有关 is_utf8 的段落。
      • 您知道检查字符串是否以 unicode 内部编码的更好方法吗?那我就换吧。
      • ITYM 说“内部编码为 UTF-8 encoding”,因为诸如 Unicode 之类的 在字符集中编码 没有任何意义。回答:你不应该关心,并且 SvUTF8 标志或它的缺失无法告诉你(这就是 is_utf8 实际检查的内容)。程序员必须只跟踪:我是否已经解码了传入的八位位组?我是否已经对传出的字符数据进行了编码? Perl 如何在内部对字符数据进行编码是它自己的事情(它比你想象的要复杂),你不应该弄乱 utf8 模块的函数。它的文档是这样说的。
      • 如果你想编写一个能正确处理 unicode 字符串并与外界对话的模块,那么你需要知道一个字符串是否以 unicode 编码(是的 unicode 不是编码并且在内部它是 utf-8,但用户不应该关心内部表示是什么,用户应该只关心它是否是 unicode)。但是请确保您也可以不在乎 unicode 并让使用您的模块的用户自己处理它,但我不喜欢它。 Perl 有 unicode 字符串,模块作者应该考虑它们。我总是对更好的方式持开放态度。 “不要这样做”不是更好的方法。
      • 抱歉,这根本不是真的。 is_utf8 不表示是否需要对某些内容进行编码。事实上,Perl 无法知道字符串是否需要编码。如果是这样,它可以自己做。 (我会详细揭穿你的说法,但这个盒子真的不适合解释任何事情。)至于做什么,你应该解码输入的所有内容并编码输出的所有内容。如果你想同时处理编码和解码的字符串,你需要手动跟踪哪个是哪个。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-04
      • 2016-06-26
      • 1970-01-01
      • 1970-01-01
      • 2021-11-06
      相关资源
      最近更新 更多