2010-09-04 108 views
11

我试过Google和StackOverflow推荐的所有内容(包括使用Encode)。我的代码工作,但它只是使用UTF8,我得到宽字符警告。我知道如何解决这些警告,但我并没有使用UTF8来处理其他任何事情,所以我只想将其转换,而不必修改其余的代码来处理它。这里是我的代码:在Perl中将UTF8字符串转换为ASCII

my $xml = XMLin($content); 
# Populate the @titles array with each item title. 
my @titles; 
for my $item (@{$xml->{channel}->{item}}) { 
    my $title = Encode::decode_utf8($item->{title}); 
    #my $title = $item->{title}; 
    #utf8::downgrade($title, 1); 
    Encode::from_to($title, 'utf8', 'iso-8859-1'); 
    push @titles, $title; 
} 
return @titles; 

注释掉你可以看到我试过的其他东西。我很清楚,我不知道我在这里做什么。我只想结束一个普通的旧ASCII字符串。任何想法将不胜感激。谢谢。

回答

18

答案取决于你想如何使用标题。有三种基本方法可供选择:

  • 表示UTF-8编码字符串的字节。

这是如果您希望在应用程序外部存储UTF-8编码字符串时使用的格式,无论是在磁盘上还是通过网络发送它或程序范围外的任何内容。

  • 一串Unicode字符。

字符的概念是Perl的内部。当您执行Encode::decode_utf8时,会尝试将一串字节转换为一串字符,如Perl所示。 Perl VM(和编写Perl代码的程序员)不能将这个概念外部化,除非通过在输入上解码UTF-8字节并将它们编码为UTF-8字节输出。例如,你的程序收到两个字节作为输入,你知道它们代表UTF-8编码的字符,比如说0xC3 0xB6。在这种情况下,decode_utf8返回一个表示,而不是两个字节,会看到一个字符:ö

然后,您可以继续在Perl中处理该字符串。为了进一步说明的差,考虑下面的代码:

my $bytes = "\xC3\xB6"; 
say length($bytes); # prints "2" 
my $string = decode_utf8($bytes); 
say length($string); # prints "1" 
  • ASCII的特殊情况,UTF-8的子集。

    ASCII是Unicode的一个非常小的子集,其中该范围内的字符由单个字节表示。将Unicode转换为ASCII是固有的有损操作,因为大多数Unicode字符不是ASCII字符。你不得不放弃你的字符串中不是ASCII码的每一个字符,或者试图从一个Unicode字符映射到最接近的ASCII字符(这在绝大多数情况下是不可能的),当试图强制一个Unicode字符串转换为ASCII。

由于您有宽字符警告,这意味着您正在尝试操作(可能输出)不能用ASCII或ISO-8859-1表示的Unicode字符。

如果您不需要将字符作为字符串处理XML文档,我建议您将其保留为UTF-8字节(我提到您应该注意不要混入字节和字符字符串)。如果您确实需要操作它,那么解码,操作和输出将以UTF-8编码。

如要进一步了解,请使用perldoc研究perlunitutperlunifaqperlunicodeperluniintro,和Encode

+1

所以基本上这是我怀疑的。我对这个问题的理解很遥远。那么,谢谢你花时间澄清。出于某种原因,我认为我能够将我的UTF8字符串强制转换为ASCII格式,这听起来像是一场混乱的黑客攻击。我想我只会打消并处理UTF8编码。 – 2010-09-04 16:40:19

+2

如果您必须将UTF-8转换为ASCII,则需要[Text :: Unidecode](http://search.cpan.org/perldoc?Text::Unidecode)。 – cjm 2010-09-04 17:59:02

+0

@cjm正是我需要的。这个将utf8字符转换为最接近的可视ASCII替代字符。非常感谢! – 2016-02-08 19:16:43

2

您可以使用以下行来简单地摆脱警告。这假定你想使用UTF8,这通常不应该是一个问题。

binmode(STDOUT, ":encoding(utf8)");

+1

您不需要冒号,但除非您使用过Perl 5.10.1或更高版本的'use autodie'编译指示,否则最好检查返回值以查看是否没有任何拼写错误。还有'PERL_UNICODE'变量,可以设置为'S'。您可以使用** - C0 **命令行标志在运行时覆盖它。更多的时候你会想要加入它,就像** - CSAD **一样。注意这一点,因为现在所有未标记的流都默认为UTF-8,这通常会给你带来麻烦。所以这不是一个好的默认。 – tchrist 2011-04-17 23:03:57

5

尽管这是一个老问题,我只花了几个小时(!)试图做或多或少同样的事情!即:从UTF-8 XML文件读取数据,并将该数据转换为Windows-1252代码页(我也可以使用Latin1,ISO-8859-1等),以便能够创建带有重音字母的文件名。

经过大量的实验,甚至更多搜索,我终于设法让转换工作。 “诀窍”是使用编码:: 编码而不是编码:: 解码

例如,给定在原始问题的代码,以从转换正确的(或至少一个:-)方式UTF-8将是:

my $title = Encode::encode("Windows-1252", $item->{title}); 

my $title = Encode::encode("ISO-8859-1", $item->{title}); 

my $title = Encode::encode("<your-favourite-codepage-here>", $item->{title}); 

我希望这可以帮助具有类似公关等oblems!