有了这个输入文件
<?xml version="1.0" encoding="UTF-8"?>
<entry>
<title>ú</title>
</entry>
Run Code Online (Sandbox Code Playgroud)
和这段代码,
my $raw_xml = read_file("test.xml", binmode => 'raw');
print "$raw_xml\n";
$raw_xml =~ /<title>(.*?)</;
print "Regex finds [$1]\n"; # prints u+accent to UTF8 terminal
my $dom = XML::LibXML->load_xml(string => $raw_xml);
my $xpc = XML::LibXML::XPathContext->new($dom);
my ($entry) = $xpc->findnodes('entry');
my $title = $xpc->findvalue('title', $entry) || '';
print "title is now [$title]\n"; # prints garbage character to UTF8 terminal, u+accent to ISO-8859-1 terminal
Run Code Online (Sandbox Code Playgroud)
哪里/为什么是完美的utf8被翻译成8位字符集之一(我假设它是8859-1,可能是cp1252等)?
我通过谷歌发现的一切都表明它应该从头到尾都是utf8.但显然不是.
注意:如果我使用binmode在文件句柄上打开文件并将其传递给load_xml,则行为完全相同; 我碰巧在实际代码中将xml存储在内存中 - 这也意味着我可以使用正则表达式进行验证.
您有两个错误,可以在第一次测试中取消产生正确的输出.
您的本土解析器不会解码文档
您可以通过更改/<title>(.*?)</为观察此错误/<title>(.)</.它不是ú按预期获得第一个字形(),而只获取其encoding(C3)的第一个字节.
要解决这个问题,请更换
$raw_xml =~ /<title>(.*?)</;
print "Regex finds [$1]\n";
Run Code Online (Sandbox Code Playgroud)
同
use Encode qw( decode_utf8 );
my $decoded_xml = decode_utf8($raw_xml);
$decoded_xml =~ /<title>(.*?)</;
print "Regex finds [$1]\n";
Run Code Online (Sandbox Code Playgroud)
现在,您从两个测试中获得相同的行为,即相同的垃圾输出.这给我们带来了第二个问题.
您不对输出进行编码
XML :: LibXML返回已解码的文本,即Unicode代码点.ú因此返回为字符,FA因为ú是U + 000FA.这是正确的,因为您不必关心编码,除非在进行I/O时.
执行I/O时会出现问题.print预计每次接收到代表一个字节的字符,所以当你告诉它打印字符FA,它打印字节FA,而你的终端变为"跆拳道?".
您的终端需要UTF-8,因此您需要UTF-8在传递字符串之前对其进行编码print,或者告诉您print为其执行此操作.
# Decode STDIN (UTF-8).
# Decode STDOUT and STDERR (UTF-8).
# The default encoding for files opened in scope is UTF-8.
use open ':std', ':encoding(UTF-8)';
Run Code Online (Sandbox Code Playgroud)
完整解决方案
use open ':std', ':encoding(UTF-8)';
use Encode qw( decode_utf8 );
my $raw_xml = read_file("test.xml", binmode => 'raw');
{
my $decoded_xml = decode_utf8($raw_xml);
my ($title) = $decoded_xml =~ /<title>(.*?)</;
printf("%s: [%s] [%s]\n", "Home-grown", $title, substr($title, 0, 1));
}
{
my $doc = XML::LibXML->load_xml(string => $raw_xml );
my ($entry_node) = $doc->findnodes('entry');
my $title = $entry->findvalue('title');
printf("%s: [%s] [%s]\n", "LibXML", $title, substr($title, 0, 1));
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
405 次 |
| 最近记录: |