encoding - 允许您用非 ASCII 和非 UTF-8 编写脚本
自 perl v5.18 起,此模块已弃用。请参阅 "描述" 和 "错误"。
use encoding "greek"; # Perl like Greek to you?
use encoding "euc-jp"; # Jperl!
# or you can even do this if your shell supports your native encoding
perl -Mencoding=latin2 -e'...' # Feeling centrally European?
perl -Mencoding=euc-kr -e'...' # Or Korean?
# more control
# A simple euc-cn => utf-8 converter
use encoding "euc-cn", STDOUT => "utf8"; while(<>){print};
# "no encoding;" supported
no encoding;
# an alternate way, Filter
use encoding "euc-jp", Filter=>1;
# now you can use kanji identifiers -- in euc-jp!
# encode based on the current locale - specialized purposes only;
# fraught with danger!!
use encoding ':locale';
此 pragma 用于使 Perl 脚本能够用非严格 ASCII 或 UTF-8 编码编写。它将 Perl 程序脚本的全部或部分内容从给定编码转换为 UTF-8,并将 STDIN
和 STDOUT
的 PerlIO 层更改为指定的编码。
这个 pragma 诞生于 UTF-8 编码编辑器并不常见的时代。但那已经是很久以前的事了,对它的需求已经大大减少。再加上它不能与线程一起使用,以及其他问题(参见 "BUGS"),导致它被弃用。计划在未来的 Perl 版本中删除这个 pragma。新的代码应该用 UTF-8 编写,并使用 use utf8
pragma 代替(有关详细信息,请参见 perluniintro 和 utf8)。旧代码应该通过类似于 "SYNOPSIS" 中的配方转换为 UTF-8(尽管这种简单的方法可能需要在之后进行手动调整)。
如果 UTF-8 不是选项,建议使用简单的源代码过滤器,例如 CPAN 上提供的 Filter::Encoding 或这个 pragma 自己的 Filter
选项(见下文)。
这个 pragma 的唯一合法用途几乎肯定只是每个文件一个,位于顶部附近,具有文件范围,因为文件很可能只用一种编码编写。在 Perl v5.22 之前的版本中,还有一些限制(参见 "Prior to Perl v5.22")。
有两种基本的操作模式(加上关闭它)。
use encoding ['ENCNAME'] ;
请注意:从 Perl v5.26 开始,这种操作模式不再受支持。
这是正常操作。它将 Perl 源文件中遇到的各种字面量从 ENCNAME 编码转换为 UTF-8,并类似地转换字符代码点。当脚本是 ASCII(用于变量名和标点符号等)的组合,但字面量数据使用指定的编码时,就会使用它。
ENCNAME 是可选的。如果省略,则使用环境变量 PERL_ENCODING
中指定的编码。如果未设置此变量,或者解析到的编码在 Encode
中未知,则会抛出错误 Unknown encoding 'ENCNAME'
。
从 Perl v5.8.6(Encode
版本 2.0.1)开始,ENCNAME 可以是名称 :locale
。这适用于非常特殊的应用程序,并在下面的 "The :locale
sub-pragma" 中有说明。
以下文字会被转换:q//
, qq//
, qr//
, qw///
, qx//
,以及从 v5.8.1 开始的 tr///
。进行转换的操作包括 chr
, ord
, utf8::upgrade
(但不包括 utf8::downgrade
),以及 chomp
。
同样从 v5.8.1 开始,DATA
伪文件句柄会从编码转换为 UTF-8。
例如,你可以用 EUC-JP 编码编写代码如下
my $Rakuda = "\xF1\xD1\xF1\xCC"; # Camel in Kanji
#<-char-><-char-> # 4 octets
s/\bCamel\b/$Rakuda/;
当 use encoding "euc-jp"
生效时,它与 UTF-8 编码的代码相同。
my $Rakuda = "\x{99F1}\x{99DD}"; # two Unicode Characters
s/\bCamel\b/$Rakuda/;
请参阅下面的 "EXAMPLE" 获取更完整的示例。
除非 ${^UNICODE}
(从 v5.8.2 开始可用)存在且不为零,否则 STDIN
和 STDOUT
的 PerlIO 层将被设置为 ":encoding(ENCNAME)
"。因此,
use encoding "euc-jp";
my $message = "Camel is the symbol of perl.\n";
my $Rakuda = "\xF1\xD1\xF1\xCC"; # Camel in Kanji
$message =~ s/\bCamel\b/$Rakuda/;
print $message;
将打印
"\xF1\xD1\xF1\xCC is the symbol of perl.\n"
而不是
"\x{99F1}\x{99DD} is the symbol of perl.\n"
你可以通过提供额外的参数来覆盖此行为;请参阅下面的内容。
请注意,STDERR
将不会被更改,无论如何。
还要注意,非 STD 文件句柄不受影响。使用 use open
或 binmode
来更改这些句柄的层。
use encoding ENCNAME, Filter=>1;
此操作与上述相同,但 Filter
参数的值不为零会导致整个脚本(而不仅仅是文字)从编码转换为 UTF-8。这允许源代码中的标识符也使用该编码。(如果编码不是 ASCII 的超集,可能会出现问题;想象一下所有分号都被转换为其他字符。)可以使用此形式来使
${"\x{4eba}"}++
工作。(这等效于 $human++
,其中 human 是一个汉字)。
这实际上意味着你的源代码的行为就像它是在 UTF-8 中使用 'use utf8
' 编写的。因此,即使你的编辑器只支持 Shift_JIS,例如,你仍然可以尝试 Programming Perl, 3rd Ed.
第 15 章中的示例。
此选项比其他选项慢得多。
no encoding;
取消设置脚本编码。STDIN
、STDOUT
的层将重置为 ":raw
"(默认的未处理原始字节流)。
STDIN
和/或 STDOUT
STDIN
和 STDOUT
的编码可以通过 pragma 的参数单独设置。
use encoding 'euc-tw', STDIN => 'greek' ...;
在这种情况下,您不能省略第一个 ENCNAME。STDIN => undef
会完全关闭该文件句柄的 I/O 转码。
当 ${^UNICODE}
(从 v5.8.2 开始可用)存在且不为零时,这些选项将被完全忽略。有关详细信息,请参阅 "${^UNICODE}
" 在 perlvar 中 和 "-C
" 在 perlrun 中。
:locale
子 pragma从 v5.8.6 开始,编码名称可以是 :locale
。这意味着编码取自当前区域设置,而不是由 pragma 硬编码。由于脚本实际上只能以一种编码编码,因此此选项很危险。只有当脚本本身是用 ASCII 编写的,并且在执行脚本时将使用的所有可能的区域设置都是 ASCII 的超集时,它才有意义。这意味着脚本本身不会改变,但 I/O 句柄会添加指定的编码,并且像 chr
和 ord
这样的操作会使用该编码。
查找 :locale
使用的区域设置的逻辑如下
如果平台支持 langinfo(CODESET)
接口,则返回的代码集将用作 open pragma 的默认编码。
如果 1. 不起作用,但我们在 locale pragma 下,则环境变量 LC_ALL
和 LANG
(按此顺序)将匹配编码(如果有,则在 ".
" 之后的部分),如果找到任何匹配项,则将其用作 open pragma 的默认编码。
如果 1. 和 2. 不起作用,则环境变量 LC_ALL
和 LANG
(按此顺序)将匹配任何看起来像 UTF-8 的内容,如果找到任何匹配项,则 :utf8
将用作 open pragma 的默认编码。
如果您的区域设置环境变量 (LC_ALL
、LC_CTYPE
、LANG
) 包含字符串 'UTF-8' 或 'UTF8'(不区分大小写匹配),则您的 STDIN
、STDOUT
和 STDERR
以及 任何后续文件打开 的默认编码为 UTF-8。
如果 encoding
pragma 在作用域内,则返回的长度将根据 $/
在 Unicode 字符中的长度计算,这并不总是与 $/
在本机编码中的长度相同。
如果没有此 pragma,如果在字节语义下操作的字符串和具有 Unicode 字符数据的字符串连接起来,则新字符串将通过将字节字符串解码为 ISO 8859-1 (Latin-1) 来创建。
编码 pragma 会将此更改为使用指定的编码。例如
use encoding 'utf8';
my $string = chr(20000); # a Unicode string
utf8::encode($string); # now it's a UTF-8 encoded byte string
# concatenate with another Unicode string
print length($string . chr(20000));
将打印 2
,因为 $string
被升级为 UTF-8。如果没有 use encoding 'utf8';
,它将打印 4
,因为 $string
在被解释为 Latin-1 时是三个字节。
请注意,只有包含传统代码点的字面量(字符串或正则表达式)会受到影响:如果你混合使用以下数据
\x{100}\xDF
\xDF\x{100}
数据被认为是 Unicode(和 Latin 1),而不是你的本地编码。换句话说,这将在“希腊语”中匹配
"\xDF" =~ /\x{3af}/
但这不是
"\xDF\x{100}" =~ /\x{3af}\x{100}/
因为左边的 \xDF
(ISO 8859-7 希腊语小写字母 IOTA 带重音)不会被升级为 \x{3af}
(Unicode 希腊语小写字母 IOTA 带重音),因为左边的 \x{100}
。你不应该在同一个字符串中混合使用传统数据和 Unicode。
此 pragma 还会影响 0x80..0xFF 代码点范围的编码:通常,该范围内的字符被保留为 8 位字节(除非它们与代码点为 0x100 或更大的字符组合,在这种情况下,所有字符都需要变为 UTF-8 编码),但如果存在 encoding
pragma,即使是 0x80..0xFF 范围也会始终被 UTF-8 编码。
毕竟,此 pragma 最棒的地方在于你无需使用 \x{....} 就能用本地编码拼写你的名字。所以,请随意将你的字符串用你的编码放在引号中,并使用正则表达式。
此 pragma 是针对每个脚本的,而不是针对每个块的词法范围的。只有最后一个 use encoding
或 no encoding
有效,它会影响整个脚本。但是,no encoding
pragma 是支持的,use encoding
可以在一个给定的脚本中出现任意多次(尽管只有最后一个有效)。
由于范围不是词法的,因此其他模块对 chr
、ord
等的使用也会受到影响。这会导致难以调试的诡异、不正确的远程操作。
这意味着你必须非常小心加载顺序
# called module
package Module_IN_BAR;
use encoding "bar";
# stuff in "bar" encoding here
1;
# caller script
use encoding "foo"
use Module_IN_BAR;
# surprise! use encoding "bar" is in effect.
避免这种怪异现象的最佳方法是在加载其他模块之后立即使用此 pragma。即
use Module_IN_BAR;
use encoding "foo";
STDIN
和 STDOUT
没有在过滤器选项下设置。并且 STDIN=>ENCODING
和 STDOUT=>ENCODING
的工作方式与非过滤器版本不同。
use utf8
没有被隐式声明,因此你必须使用 use utf8
来执行
${"\x{4eba}"}++
由于 Perl 需要在应用此 pragma 之前解析脚本,因此诸如 Shift_JIS 和 Big-5 之类的编码可能包含 '\'
(反斜杠;\x5c
)在第二个字节中失败,因为第二个字节可能会意外地转义后面的引号字符。
tr///
encoding pragma 通过解码 q//,qq//,qr//,qw///, qx//
等中的字符串字面量来工作。在 perl v5.8.0 中,这并不适用于 tr///
。因此,
use encoding 'euc-jp';
#....
$kana =~ tr/\xA4\xA1-\xA4\xF3/\xA5\xA1-\xA5\xF3/;
# -------- -------- -------- --------
不起作用,因为
$kana =~ tr/\x{3041}-\x{3093}/\x{30a1}-\x{30f3}/;
utf8 euc-jp charnames::viacode()
-----------------------------------------
\x{3041} \xA4\xA1 HIRAGANA LETTER SMALL A
\x{3093} \xA4\xF3 HIRAGANA LETTER N
\x{30a1} \xA5\xA1 KATAKANA LETTER SMALL A
\x{30f3} \xA5\xF3 KATAKANA LETTER N
这种反直觉的行为已在 perl v5.8.1 中修复。
在 perl v5.8.0 中,您可以通过以下方式解决此问题;
use encoding 'euc-jp';
# ....
eval qq{ \$kana =~ tr/\xA4\xA1-\xA4\xF3/\xA5\xA1-\xA5\xF3/ };
请注意,tr//
表达式被 qq{}
包围。这背后的想法与使 tr///
'插值' 的经典习惯用法相同。
tr/$from/$to/; # wrong!
eval qq{ tr/$from/$to/ }; # workaround.
use encoding "iso 8859-7";
# \xDF in ISO 8859-7 (Greek) is \x{3af} in Unicode.
$a = "\xDF";
$b = "\x{100}";
printf "%#x\n", ord($a); # will print 0x3af, not 0xdf
$c = $a . $b;
# $c will be "\x{3af}\x{100}", not "\x{df}\x{100}".
# chr() is affected, and ...
print "mega\n" if ord(chr(0xdf)) == 0x3af;
# ... ord() is affected by the encoding pragma ...
print "tera\n" if ord(pack("C", 0xdf)) == 0x3af;
# ... as are eq and cmp ...
print "peta\n" if "\x{3af}" eq pack("C", 0xdf);
print "exa\n" if "\x{3af}" cmp pack("C", 0xdf) == 0;
# ... but pack/unpack C are not affected, in case you still
# want to go back to your native encoding
print "zetta\n" if unpack("C", (pack("C", 0xdf))) == 0xdf;
use encoding ...
不是线程安全的(即,不要在多线程应用程序中使用)。
只允许一种编码。如果您在一个程序中组合了具有不同编码的模块,则实际上只使用一种编码。
STDIN
和 STDOUT
的其他模块会获得编码后的流它们可能期望完全不同的东西。
对于本机多字节编码(固定或可变长度),正则表达式的当前实现可能会为长度超过 127 字节的正则表达式字面量引入重新编码错误。
encoding pragma 在 EBCDIC 平台上不受支持。
format
此 pragma 与 format
配合得不好,因为 PerlIO 与它配合得不好。当 format
包含非 ASCII 字符时,它会打印奇怪的内容或出现“宽字符警告”。要理解它,请尝试以下代码。
# Save this one in utf8
# replace *non-ascii* with a non-ascii string
my $camel;
format STDOUT =
*non-ascii*@>>>>>>>
$camel
.
$camel = "*non-ascii*";
binmode(STDOUT=>':encoding(utf8)'); # bang!
write; # funny
print $camel, "\n"; # fine
如果没有 binmode,这似乎可以工作,但如果没有 binmode,print() 会失败,而不是 write()。
无论如何,在处理 Unicode 字符时,使用 format
本身就很值得怀疑,因为您必须考虑诸如字符宽度(例如,象形文字的双宽度)和方向(例如,阿拉伯语和希伯来语的双向文本)等因素。
此 pragma 首次出现在 Perl v5.8.0 中。它在随后的版本中得到了增强,如上所述。
perlunicode,Encode,open,Filter::Util::Call,
Larry Wall、Tom Christiansen 和 Jon Orwant 合著的《Programming Perl (第 3 版)》第 15 章;O'Reilly & Associates;ISBN 0-596-00027-8