gpt4 book ai didi

Perl:utf8::decode 与 Encode::decode

转载 作者:行者123 更新时间:2023-12-04 12:14:05 27 4
gpt4 key购买 nike

我得到了一些有趣的结果,试图辨别使用 Encode::decode("utf8", $var) 之间的区别。和 utf8::decode($var) .我已经发现,在一个变量上多次调用前者最终会导致错误“无法在...处解码带有宽字符的字符串”,而后一种方法会很高兴地运行任意多次,只是返回 false。

我无法理解的是 length函数根据您用于解码的方法返回不同的结果。出现问题是因为我正在处理来自外部文件的“双重编码”utf8 文本。为了演示这个问题,我创建了一个文本文件“test.txt”,其中一行包含以下 Unicode 字符:U+00e8、U+00ab、U+0086、U+000a。这些 Unicode 字符是 Unicode 字符 U+8acb 和换行符的双重编码。该文件以 UTF8 编码到磁盘。然后我运行以下 perl 脚本:

#!/usr/bin/perl                                                                                                                                          
use strict;
use warnings;
require "Encode.pm";
require "utf8.pm";

open FILE, "test.txt" or die $!;
my @lines = <FILE>;
my $test = $lines[0];

print "Length: " . (length $test) . "\n";
print "utf8 flag: " . utf8::is_utf8($test) . "\n";
my @unicode = (unpack('U*', $test));
print "Unicode:\n@unicode\n";
my @hex = (unpack('H*', $test));
print "Hex:\n@hex\n";

print "==============\n";

$test = Encode::decode("utf8", $test);
print "Length: " . (length $test) . "\n";
print "utf8 flag: " . utf8::is_utf8($test) . "\n";
@unicode = (unpack('U*', $test));
print "Unicode:\n@unicode\n";
@hex = (unpack('H*', $test));
print "Hex:\n@hex\n";

print "==============\n";

$test = Encode::decode("utf8", $test);
print "Length: " . (length $test) . "\n";
print "utf8 flag: " . utf8::is_utf8($test) . "\n";
@unicode = (unpack('U*', $test));
print "Unicode:\n@unicode\n";
@hex = (unpack('H*', $test));

print "Hex:\n@hex\n";

这给出了以下输出:

长度:7
utf8 标志:
统一码:
195 168 194 171 194 139 10
十六进制:
c3a8c2abc28b0a
===============
长度:4
UTF8 标志:1
统一码:
232 171 139 10
十六进制:
c3a8c2abc28b0a
===============
长度:2
UTF8 标志:1
统一码:
35531 10
十六进制:
e8ab8b0a

这是我所期望的。长度原来是 7,因为 perl 认为 $test 只是一系列字节。解码一次后,perl 知道 $test 是一系列 utf8 编码的字符(即 perl 不是返回 7 个字节的长度,而是返回 4 个字符的长度,即使 $test 在内存中仍然是 7 个字节)。在第二次解码之后, $test 包含解释为 2 个字符的 4 个字节,这是我所期望的,因为 Encode::decode 采用 4 个代码点并将它们解释为 utf8 编码的字节,从而产生 2 个字符。奇怪的是,当我修改代码以调用 utf8::decode 时(将所有 $test = Encode::decode("utf8", $test); 替换为 utf8::decode($test))

这给出了几乎相同的输出,只是长度的结果不同:

长度:7
utf8 标志:
统一码:
195 168 194 171 194 139 10
十六进制:
c3a8c2abc28b0a
===============
长度:4
UTF8 标志:1
统一码:
232 171 139 10
十六进制:
c3a8c2abc28b0a
===============
长度:4
UTF8 标志:1
统一码:
35531 10
十六进制:
e8ab8b0a

似乎 perl 在解码之前首先计算字节数(如预期的那样),然后在第一次解码后计算字符数,然后在第二次解码后再次计算字节数(不是预期的)。为什么会发生这种转变?我对这些解码功能如何工作的理解有偏差吗?

谢谢,马特

最佳答案

您不应该使用 utf8 中的函数语用模块。 Its documentation这么说:

Do not use this pragma for anything else than telling Perl that your script is written in UTF-8.



Always use the Encode module ,另见问题 Checklist for going the Unicode way with Perl . unpack太低级了,它甚至没有给你错误检查。

您错误地假设八进制 E8 AB 86 0A是 UTF-8 的结果双编码 字符 newline .这是 的表示单 UTF-8 编码 这些字符中。也许你身边的整个困惑源于那个错误。
length被不恰本地重载,在某些时候它决定了字符的长度,或者八位字节的长度。使用更好的工具,例如 Devel::Peek .
#!/usr/bin/env perl
use strict;
use warnings FATAL => 'all';
use Devel::Peek qw(Dump);
use Encode qw(decode);

my $test = "\x{00e8}\x{00ab}\x{0086}\x{000a}";
# or read the octets without implicit decoding from a file, does not matter

Dump $test;
# FLAGS = (PADMY,POK,pPOK)
# PV = 0x8d8520 "\350\253\206\n"\0

$test = decode('UTF-8', $test, Encode::FB_CROAK);
Dump $test;
# FLAGS = (PADMY,POK,pPOK,UTF8)
# PV = 0xc02850 "\350\253\206\n"\0 [UTF8 "\x{8ac6}\n"]

关于Perl:utf8::decode 与 Encode::decode,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4339377/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com