如何从Perl输出UTF-8?


110

我正在尝试使用“ utf8”编译指示来编写Perl脚本,并且得到了意外的结果。我正在使用Mac OS X 10.5(Leopard),并且正在使用TextMate进行编辑。我的编辑器和操作系统的所有设置都默认为以utf-8格式写入文件。

但是,当我在文本文件中输入以下内容,将其另存为“ .pl”并执行时,我得到了友好的“带问号的钻石”来代替非ASCII字符。

#!/usr/bin/env perl -w

use strict;
use utf8;

my $str = 'Çirçös';
print( "$str\n" );

知道我在做什么错吗?我期望在输出中得到'Çirçös',但是我得到的是'.ir s'。


1
也许不是程序..我认为它是您的外壳还是您的编辑器,它可以完成输出
n00ki3,2009年

所有答案都正确回答了您的问题,如何将其显式设置为UTF8。我认为您应该调整终端的语言环境设置,如stackoverflow.com/a/14405949/498634所示。终端可能未设置为UTF8,然后以UTF8格式写入STDOUT的数据将被错误编码
DanielBöhmer19年

很好的答案如何一起工作utf8
Eugen Konkov

Answers:


160

use utf8;不启用Unicode 输出 -它使您可以在程序中键入Unicode。在您print()声明之前,将其添加到程序中:

binmode(STDOUT, ":utf8");

看看是否有帮助。那应该STDOUT以UTF-8而不是普通的ASCII输出。


我对此一无所知(我只是将UTF8放入数据库中,从未打印过它)。+1。
Paul Tomblin,2009年

1
别客气。另请参见另一个正确答案:stackoverflow.com/questions/627661/writing-perl-code-in-utf8/…请记住,TMTOWTDI。而@保罗-如果你正在写UTF-8到一个文件,你应该对文件句柄使用binmode()并使其“适当的” UTF-8,但如果它的工作原理..
克里斯·鲁茨

1
其他的方法:打开编译指示(search.cpan.org/perldoc/open),-C开关(perldoc.perl.org/perlrun.html#-C
YSTH

1
这是FWIW的原因:仅包含latin1(ISO-8859-1)字符的字符串,尽管或多或少地存储在utf8中,但默认情况下将作为latin1输出。这样,即使使用支持unicode的perl,来自pre-unicode时代的脚本仍然可以正常工作。
mirod

3
utf8编译指示不允许您使用UNICODE编写源代码,而是通过UNICODE的UTF-8(或UTF-EBCDIC)编码(一个重要的区别)来强制理解源代码。
Chas。Owens

83

您可以使用开放式编译指示

例如。下面将STDOUT,STDIN和STDERR设置为使用UTF-8...。

use open qw/:std :utf8/;

1
顺便说一句...我给了你+1。我认为binmode(STDOUT,':utf8')在这种情况下可能更正确。“ use open”还有其他很好的用途,但是我似乎找不到如何将其设置为仅编码STDOUT的方法?
draegtun

66

TMTOWTDI,选择了最适合您工作方式的方法。我使用环境方法,因此无需考虑。

环境中

export PERL_UNICODE=SDL

命令行上

perl -CSDL -le 'print "\x{1815}"';

或使用binmode

binmode(STDOUT, ":utf8");          #treat as if it is UTF-8
binmode(STDIN, ":encoding(utf8)"); #actually check if it is UTF-8

或使用PerlIO

open my $fh, ">:utf8", $filename
    or die "could not open $filename: $!\n";

open my $fh, "<:encoding(utf-8)", $filename
    or die "could not open $filename: $!\n";

或使用开放式编译指示

use open ":encoding(utf8)";
use open IN => ":encoding(utf8)", OUT => ":utf8";

1
+1获得全面答案;需要注意的是SDL既具有隐含-CPERL_UNICODEuse open ':locale'值得一提的是该实用程序,因为它在脚本中等同于-Cexport PER_UNICODE=。假设您环境的语言环境是基于UTF8的,那么这3个中的任何一个都将为您提供对所有输入和输出流(无论是文件还是stdin / stdout / stderr)的UTF8支持。最后,也要将代码视为UTF8,请使用use utf8;编译指示。
mklement0 2014年

perl -Mutf8 -CSDL -e '...'允许使用/输出UTF-8 以及在内部使用UTF-8文字,-e例如用于穷人的案件文件夹:perl -Mutf8 -CASDL -pe 'y/āáǎàēéěèīíǐìōóǒòūúǔùǖǘǚǜĀÁǍÀĒÉĚÈĪÍǏÌŌÓǑÒŪÚǓÙǕǗǙǛ/aaaaeeeeiiiioooouuuuüüüüAAAAEEEEIIIIOOOOUUUUÜÜÜÜ/'
vladr


0

谢谢,终于有了一个解决方案,不要在整个代码中都放置utf8 :: encode。要综合和完成其他情况,例如在utf8中写入和读取文件,并且还可以与utf8中的YAML文件的LoadFile一起使用

use utf8;
use open ':encoding(utf8)';
binmode(STDOUT, ":utf8");

open(FH, ">test.txt"); 
print FH "something éá";

use YAML qw(LoadFile Dump);
my $PUBS = LoadFile("cache.yaml");
my $f = "2917";
my $ref = $PUBS->{$f};
print "$f \"".$ref->{name}."\" ". $ref->{primary_uri}." ";

其中cache.yaml是:

---
2917:
  id: 2917
  name: Semanário
  primary_uri: 2917.xml

-3

在您的shell中执行:$ env | grep LANG

这可能表明您的外壳未使用utf-8语言环境。


实际上,它设置为utf-8。问题是我在没有将binmode设置为utf-8的情况下输出到STDOUT。

2
这将是一个正交的问题。您需要使用Perl脚本输出正确的数据,然后才能担心终端仿真器如何解释它。
jrockway
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.