【问题标题】:How do you change the encoding of a file, using Perl?如何使用 Perl 更改文件的编码?
【发布时间】:2013-05-23 17:11:25
【问题描述】:

我正在编写一个创建 xml 文件“settings.xml”的 perl 脚本。 (使用 XML::Writer)。我希望文件以 UCS-2 大端编码,但我不确定如何。

我尝试过类似:open(my $output, "> :encoding(UCS-2BE)", "settings.xml");,但所做的只是让文件输出一团糟(例如http://i.imgur.com/p9cruCf.png 或一系列汉字),同时保持文件的编码为 ANSI。

知道如何解决此问题,或者如何将文件转换为 UCS-2?

我是 Perl 的初学者,如果其中一些没有意义,请见谅。

编辑:对于遇到此问题的其他人,请参阅下面的答案,他们提供了有关如何解决此问题的详尽说明。

【问题讨论】:

  • 您是否尝试在写入文件之前强制对内容进行编码? perldoc.perl.org/Encode/Unicode.html
  • 从 ASCII 转换为 UCS-2 只需将每个 7 位值扩大到 16 位。您预计会有哪些变化?

标签: perl encoding ucs2


【解决方案1】:

XML::Writer 不支持除 US-ASCII 和 UTF-8 之外的任何内容(如其 ENCODING 构造函数参数的文档中所述)。使用 XML::Writer 创建 UCS-2be XML 文档很棘手,但并非不可能。

use XML::Writer qw( );

# XML::Writer doesn't encode for you, so we need to use :encoding.
# The :raw avoids a problem with CRLF conversion on Windows.
open(my $fh, '>:raw:encoding(UCS-2be)', $qfn)
   or die("Can't create \"$qfn\": $!\n");

# This prints the BOM. It's optional, but it's useful when using an
# encoding that's not a superset of US-ASCII (such as UCS-2be).
print($fh "\x{FEFF}");

my $writer = XML::Writer->new(
   OUTPUT   => $fh,
   ENCODING => 'US-ASCII',   # Use entities for > U+007F
);
$writer->xmlDecl('UCS-2be');
$writer->startTag('root');
$writer->characters("\x{00041}");
$writer->characters("\x{000C9}");
$writer->characters("\x{10000}");
$writer->endTag();
$writer->end();

缺点:U+007F 以上的所有字符都将显示为 XML 实体。在上面的例子中,

  • U+00041 将显示为“A”(00 41)。很好。
  • U+000C9 将显示为“É”(00 26 00 23 00 78 00 43 00 39 00 3B)。次优,但还可以。
  • U+10000 将显示为“𐀀”(00 26 00 23 00 78 00 31 00 30 00 30 00 30 00 30 00 3B)。很好,需要 XML 实体来存储 U+10000 和 UCB-2e

当且仅当您可以保证不会向作者提供任何高于 U+FFFF 的字符时,您才能避免上述不利因素。

use XML::Writer qw( );

# XML::Writer doesn't encode for you, so we need to use :encoding.
# The :raw avoids a problem with CRLF conversion on Windows.
open(my $fh, '>:raw:encoding(UCS-2be)', $qfn)
   or die("Can't create \"$qfn\": $!\n");

# This prints the BOM. It's optional, but it's useful when using an
# encoding that's not a superset of US-ASCII (such as UCS-2be).
print($fh "\x{FEFF}");

my $writer = XML::Writer->new(
   OUTPUT   => $fh,
   ENCODING => 'UTF-8',   # Don't use entities.
);
$writer->xmlDecl('UCS-2be');
$writer->startTag('root');
$writer->characters("\x{00041}");
$writer->characters("\x{000C9}");
#$writer->characters("\x{10000}");  # This causes a fatal error
$writer->endTag();
$writer->end();
  • U+00041 将显示为“A”(00 41)。很好。
  • U+000C9 将显示为“É”(00 C9)。很好。
  • U+10000 导致致命错误。

以下是您可以在没有任何缺点的情况下做到这一点的方法:

use Encode      qw( decode encode );
use XML::Writer qw( );

my $xml;
{
   # XML::Writer doesn't encode for you, so we need to use :encoding.
   open(my $fh, '>:encoding(UTF-8)', \$xml);

   # This prints the BOM. It's optional, but it's useful when using an
   # encoding that's not a superset of US-ASCII (such as UCS-2be).
   print($fh "\x{FEFF}");

   my $writer = XML::Writer->new(
      OUTPUT   => $fh,
      ENCODING => 'UTF-8',   # Don't use entities.
   );
   $writer->xmlDecl('UCS-2be');
   $writer->startTag('root');
   $writer->characters("\x{00041}");
   $writer->characters("\x{000C9}");
   $writer->characters("\x{10000}");
   $writer->endTag();
   $writer->end();
   close($fh);
}

# Fix encoding.
$xml = decode('UTF-8', $xml);
$xml =~ s/([^\x{0000}-\x{FFFF}])/ sprintf('&#x%X;', ord($1)) /eg;
$xml = encode('UCS-2be', $xml);

open(my $fh, '>:raw', $qfn)
   or die("Can't create \"$qfn\": $!\n");

print($fh $xml);
  • U+00041 将显示为“A”(00 41)。很好。
  • U+000C9 将显示为“É”(00 C9)。很好。
  • U+10000 将显示为“𐀀”(00 26 00 23 00 78 00 31 00 30 00 30 00 30 00 30 00 3B)。很好,需要 XML 实体来存储 U+10000 和 UCB-2e

【讨论】:

  • 糟糕,修复了第二个 sn-p 中的错误。
  • 添加了一个没有任何缺点的版本。
  • 哇!这工作得很好,谢谢!由于我可以保证没有高于 UTF-FFFF 的字符,因此我使用了您的第二个选项,并且效果很好。似乎我缺少的是字节顺序标记和open(my $fh, '>:raw:encoding(UCS-2be)', $qfn):raw 部分。话虽如此,我还花时间复习了您所写的其余内容,并对编码进行了更多研究以补充我不理解的内容。所以感谢您帮助初学者了解更多!
【解决方案2】:

您没有描述出了什么问题,但是您可能遇到了一些 perl 版本在 Windows 上的错误,即编码和 crlf 层之间的交互不良。如果是这样,这应该有效:

open(my $output, "> :raw:perlio:encoding(UCS-2BE):crlf:utf8", "settings.xml");

(有关说明,请参阅http://www.perlmonks.org/?node_id=608532。)

如果不是,请提供比“所做的只是使文件输出一团糟”以外的更多信息。演示该问题的简短脚本会很有帮助。

【讨论】:

  • 抱歉。发生的事情是两件事之一,要么我得到一长串日文(或中文)字符,要么文件中的每个字符都被一个黑条替换,里面有“NULL”。使用您的解决方案,包含的屏幕截图是我的结果。 (但我意识到,我提供的信息缺乏确实没有帮助您缩小我的问题所在。i.imgur.com/p9cruCf.png 但是,使用此处的其他答案,我设法解决了问题,但感谢您抽出宝贵时间回应。
猜你喜欢
  • 2013-08-27
  • 1970-01-01
  • 2010-10-21
  • 1970-01-01
  • 2011-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-19
相关资源
最近更新 更多