内容

名称

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,并将 STDINSTDOUT 的 PerlIO 层更改为指定的编码。

这个 pragma 诞生于 UTF-8 编码编辑器并不常见的时代。但那已经是很久以前的事了,对它的需求已经大大减少。再加上它不能与线程一起使用,以及其他问题(参见 "BUGS"),导致它被弃用。计划在未来的 Perl 版本中删除这个 pragma。新的代码应该用 UTF-8 编写,并使用 use utf8 pragma 代替(有关详细信息,请参见 perluniintroutf8)。旧代码应该通过类似于 "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 开始可用)存在且不为零,否则 STDINSTDOUT 的 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 openbinmode 来更改这些句柄的层。

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;

取消设置脚本编码。STDINSTDOUT 的层将重置为 ":raw"(默认的未处理原始字节流)。

OPTIONS

单独设置 STDIN 和/或 STDOUT

STDINSTDOUT 的编码可以通过 pragma 的参数单独设置。

use encoding 'euc-tw', STDIN => 'greek'  ...;

在这种情况下,您不能省略第一个 ENCNAMESTDIN => undef 会完全关闭该文件句柄的 I/O 转码。

${^UNICODE}(从 v5.8.2 开始可用)存在且不为零时,这些选项将被完全忽略。有关详细信息,请参阅 "${^UNICODE}" 在 perlvar 中"-C" 在 perlrun 中

:locale 子 pragma

从 v5.8.6 开始,编码名称可以是 :locale。这意味着编码取自当前区域设置,而不是由 pragma 硬编码。由于脚本实际上只能以一种编码编码,因此此选项很危险。只有当脚本本身是用 ASCII 编写的,并且在执行脚本时将使用的所有可能的区域设置都是 ASCII 的超集时,它才有意义。这意味着脚本本身不会改变,但 I/O 句柄会添加指定的编码,并且像 chrord 这样的操作会使用该编码。

查找 :locale 使用的区域设置的逻辑如下

  1. 如果平台支持 langinfo(CODESET) 接口,则返回的代码集将用作 open pragma 的默认编码。

  2. 如果 1. 不起作用,但我们在 locale pragma 下,则环境变量 LC_ALLLANG(按此顺序)将匹配编码(如果有,则在 "." 之后的部分),如果找到任何匹配项,则将其用作 open pragma 的默认编码。

  3. 如果 1. 和 2. 不起作用,则环境变量 LC_ALLLANG(按此顺序)将匹配任何看起来像 UTF-8 的内容,如果找到任何匹配项,则 :utf8 将用作 open pragma 的默认编码。

如果您的区域设置环境变量 (LC_ALLLC_CTYPELANG) 包含字符串 'UTF-8' 或 'UTF8'(不区分大小写匹配),则您的 STDINSTDOUTSTDERR 以及 任何后续文件打开 的默认编码为 UTF-8。

注意事项

副作用

不要混合使用多种编码

请注意,只有包含传统代码点的字面量(字符串或正则表达式)会受到影响:如果你混合使用以下数据

\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{....} 就能用本地编码拼写你的名字。所以,请随意将你的字符串用你的编码放在引号中,并使用正则表达式。

Perl v5.22 之前

此 pragma 是针对每个脚本的,而不是针对每个块的词法范围的。只有最后一个 use encodingno encoding 有效,它会影响整个脚本。但是,no encoding pragma 是支持的,use encoding 可以在一个给定的脚本中出现任意多次(尽管只有最后一个有效)。

由于范围不是词法的,因此其他模块对 chrord 等的使用也会受到影响。这会导致难以调试的诡异、不正确的远程操作。

这意味着你必须非常小心加载顺序

# 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";

Encode 版本 1.87 之前

Perl v5.8.1 之前

"非 EUC" 双字节编码

由于 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.

示例 - Greekperl

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 ... 不是线程安全的(即,不要在多线程应用程序中使用)。

不能在单个程序中被多个模块使用。

只允许一种编码。如果您在一个程序中组合了具有不同编码的模块,则实际上只使用一种编码。

使用 STDINSTDOUT 的其他模块会获得编码后的流

它们可能期望完全不同的东西。

正则表达式中长度超过 127 字节的字面量

对于本机多字节编码(固定或可变长度),正则表达式的当前实现可能会为长度超过 127 字节的正则表达式字面量引入重新编码错误。

EBCDIC

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 本身就很值得怀疑,因为您必须考虑诸如字符宽度(例如,象形文字的双宽度)和方向(例如,阿拉伯语和希伯来语的双向文本)等因素。

另请参阅 "CAVEATS"

历史

此 pragma 首次出现在 Perl v5.8.0 中。它在随后的版本中得到了增强,如上所述。

另请参阅

perlunicodeEncodeopenFilter::Util::Call

Larry Wall、Tom Christiansen 和 Jon Orwant 合著的《Programming Perl (第 3 版)》第 15 章;O'Reilly & Associates;ISBN 0-596-00027-8