HTML 的 Perl 多字节字符编码
Perl multi-byte character encoding for HTML
正在向我传递一个字符串,例如:
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::encode
和 HTML::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 期望源是 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;
.
- ASCII 的 8 位干净版本,这意味着在字符串或正则表达式文字中设置第 8 位的任何字节都会产生具有相同值的字符。
正如@ikegami 所说,use utf8;
将从 UTF-8 解码您的源代码,以便可以按预期解释字符串文字和其他符号。与源代码一样,代码的输入也是以字节为单位的,如果是文本,则通常采用 UTF-8 编码。因此,根据它的来源,您有多种选择可以将其解码为有用的字符。下面列出了不同的选项,您只需要一个用于特定的输入流。
来自标准输入:
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
或者这些开关用于 oneliner:
-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
或者这些开关用于 oneliner:
-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。
一些有用的链接:
- open pragma
- -C switch
- utf8 pragma+functions
- Encode
- Encode::Simple
- perlunitut
- more than you ever need to know about handling UTF-8 in Perl
正在向我传递一个字符串,例如:
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::encode
和 HTML::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 期望源是 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;
.
- ASCII 的 8 位干净版本,这意味着在字符串或正则表达式文字中设置第 8 位的任何字节都会产生具有相同值的字符。
正如@ikegami 所说,use utf8;
将从 UTF-8 解码您的源代码,以便可以按预期解释字符串文字和其他符号。与源代码一样,代码的输入也是以字节为单位的,如果是文本,则通常采用 UTF-8 编码。因此,根据它的来源,您有多种选择可以将其解码为有用的字符。下面列出了不同的选项,您只需要一个用于特定的输入流。
来自标准输入:
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
或者这些开关用于 oneliner:
-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
或者这些开关用于 oneliner:
-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。
一些有用的链接:
- open pragma
- -C switch
- utf8 pragma+functions
- Encode
- Encode::Simple
- perlunitut
- more than you ever need to know about handling UTF-8 in Perl