HTML的Perl多字节字符编码

问题描述 投票:1回答:2

我正在传递一个字符串,例如:

my $x = "Zakłady Kuźnicze";

如果仔细检查,您会发现那两个奇怪的字母实际上是由两个字节组成的:

foreach (split(//, $x)) { print $_.' '.ord($_)."\n"; }

Z 90
a 97
k 107
� 197
� 130
a 97
d 100
y 121
  32
K 75
u 117
� 197
� 186
n 110
i 105
c 99
z 122
e 101

我想使用此处描述的代码将其转换为编码的HTML:https://www.w3schools.com/charsets/ref_utf_latin_extended_a.asp

所以我需要一个这样的功能:

print encode_it($x)."\n";

产量:

Zakłady Kužnice

我已经尝试过HTML::Entities::encodeHTML::Entities::encode_numeric,但是这些结果:

Zakłady Kuźnicze

Zakłady Kuźnicze

这没有帮助,它呈现为:

Zakłady Kuźnicze

任何人都可以建议如何实现这一目标吗?

编辑:

像ikegami所示,如果使用use utf8并且在程序中设置了字符串,则可以正常工作:

perl -e 'use utf8; chomp; printf "%X\n", ord for split //, "Zakłady Kuźnicze"'
5A
61
6B
142
61
64
79
20
4B
75
17A
6E
69
63
7A
65

...但是我的输入实际上是通过STDIN输入的,并且在STDIN中不起作用:

echo "Zakłady Kuźnicze" | perl -ne 'use utf8; chomp; printf "%X\n", ord for split //'
5A
61
6B
C5
82
61
64
79
20
4B
75
C5
BA
6E
69
63
7A
65

我在这里想念什么精妙之处?

perl character-encoding multibyte
2个回答
3
投票

Perl希望源是ASCII [1](默认为no utf8;)或UTF-8(use utf8;)。您似乎有一个使用UTF-8编码的文件,但是您没有告诉Perl,因此它看到

my $x = "Zak\xC5\x82ady Ku\xC5\xBAnicze";

而不是预期的

my $x = "Zak\x{142}ady Ku\x{17A}nicze";

示例(UTF-8终端):

$ diff -U 0 \
   <( perl -e'no utf8;  printf "%X\n", ord for split //, "Zakłady Kuźnicze"' ) \
   <( perl -e'use utf8; printf "%X\n", ord for split //, "Zakłady Kuźnicze"' )
--- /dev/fd/63  2020-01-17 20:04:23.407591294 -0800
+++ /dev/fd/62  2020-01-17 20:04:23.407591294 -0800
@@ -4,2 +4 @@
-C5
-82
+142
@@ -12,2 +11 @@
-C5
-BA
+17A

添加use utf8;


  1. ASCII的8位纯净版本,意味着在字符串或正则表达式文字中设置了第8位的任何字节都将产生具有相同值的字符。

0
投票

[正如@ikegami所说,use utf8;将从UTF-8解码您的源代码,以便可以按预期解释字符串文字和其他符号。与源代码一样,代码的输入也以字节为单位,如果是文本,则通常以UTF-8编码。因此,根据其来源,您有几种选择可以将其解码为有用的字符。下面列出了不同的选项,对于特定的输入流,只需一个即可。

来自STDIN:

use open ':std', IN => ':encoding(UTF-8)'; # also affects read filehandles opened in this scope
use open ':std', ':encoding(UTF-8)'; # also affects STDOUT, STDERR, and all filehandles opened in this scope
binmode *STDIN, ':encoding(UTF-8)'; # STDIN only

或这些用于单线的开关:

-CI # STDIN only
-CS # STDIN, STDOUT, STDERR
-Mopen=':std,IN,:encoding(UTF-8)' # equivalent to first "use open" above

从句柄中打开自己:

use open IN => ':encoding(UTF-8)'; # all read handles opened in this scope
use open ':encoding(UTF-8)'; # also affects write handles
open my $fh, '<:encoding(UTF-8)', 'example.txt' or die "Failed to open example.txt: $!";
binmode $fh, ':encoding(UTF-8)'; # to set on already opened handle

或这些用于单线的开关:

-Ci # read handles only
-CD # all handles opened
-Mopen='IN,:encoding(UTF-8)' # equivalent to first "use open" above

上面的use open-C选项也适用于ARGV(-n-p<> / readline运算符用于读取作为参数传递的文件名的句柄-这与用于读取STDIN时)。可以组合-C开关,例如-CSD会将其设置为STDIN / OUT / ERR以及所有打开的手柄。

最后,您可以在读取后解码数据本身,而不是全局影响任何句柄(假设数据位于$_中:]

utf8::decode($_) or die "Invalid UTF-8"; # in place, does not require "use utf8"
$_ = Encode::decode('UTF-8', $_); # with Encode loaded
$_ = Encode::Simple::decode_utf8($_); # with Encode::Simple loaded

[请记住,如果您要输出这样的解码字符,或为源代码设置了use utf8;的文字输出字符,则STDOUT,STDERR和其他写入句柄需要进行相同的处理,或者您需要将数据编码为UTF -8在打印之前。

一些有用的链接:

© www.soinside.com 2019 - 2024. All rights reserved.