perlebcdic - 在 EBCDIC 平台上运行 Perl 的注意事项
探讨了 EBCDIC 基于计算机的 Perl 程序员面临的一些问题。
本文档中仍未完成的部分用 XXX 标记。
早期的 Perl 版本在一些 EBCDIC 机器上运行,但最后一个在 EBCDIC 上运行的已知版本是 v5.8.7,直到 v5.22,Perl 核心才再次在 z/OS 上运行。理论上,它可以在 OS/400 或西门子的 BS2000(或其后续版本)上运行,但这尚未经过测试。在 v5.22 和 5.24 中,并非所有在 CPAN 上找到但与 Perl 核心一起提供的模块都可以在 z/OS 上运行。
如果您想在非 z/OS EBCDIC 机器上使用 Perl,请在 https://github.com/Perl/perl5/issues 上告知我们。
在 EBCDIC 平台上编写 Perl 与在 "ASCII" 平台上编写并没有什么不同,只是底层数字不同,我们很快就会看到。您需要了解一些关于 "ASCII" 平台的信息,因为文档存在偏差,并且经常使用不适用于 EBCDIC 的示例数字。此外,很少有为 EBCDIC 编写的 CPAN 模块,这些模块在 ASCII 上无法运行;相反,绝大多数 CPAN 模块都是为 ASCII 编写的,有些可能恰好在 EBCDIC 上运行,而有些则被设计为可移植地在两者上运行。
如果您的代码只使用 52 个字母 A-Z 和 a-z,加上空格、数字 0-9 和 Perl 使用的标点符号,以及一些由转义序列表示的控制字符,例如 \n
和 \t
,那么使用 Perl 就没有特殊之处,您的代码很可能在 ASCII 机器上无需更改即可运行。
但是,如果您编写的代码使用\005
表示制表符,或使用\xC1
表示“A”,或使用\xDF
表示“ÿ”(带分音符的小"y"
),那么您的代码可能在您的 EBCDIC 平台上运行良好,但在 ASCII 平台上则不行。如果您不打算在 ASCII 平台上运行您的代码,这样做是可以的;但本文档将倾向于编写可在 EBCDIC 和 ASCII 系统之间移植的代码。同样,如果您关心的每个字符都可以在您的键盘上轻松输入,那么您无需了解 ASCII,但许多键盘并不允许您直接输入,例如,字符\xDF
,因此您必须使用间接方式指定它,例如使用"\xDF"
转义序列。在这种情况下,了解 ASCII/Unicode 字符集最容易。如果您知道小“ÿ”是U+00FF
,那么您可以将其指定为"\N{U+FF}"
,并让计算机自动将其转换为您的平台上的\xDF
,并在 ASCII 平台上将其保留为\xFF
。或者,您可以按名称指定它,\N{LATIN SMALL LETTER Y WITH DIAERESIS
,而无需知道数字。两种方法都可以,但都需要熟悉 Unicode。
美国信息交换标准代码(ASCII 或 US-ASCII)是一组从 0 到 127(十进制)的整数,这些整数在使用 ASCII 的计算机中具有标准化的解释。例如,65 表示字母“A”。范围 0..127 可以通过设置 7 位二进制数字中的各种位来覆盖,因此该集合有时被称为“7 位 ASCII”。ASCII 由美国国家标准学会文档 ANSI X3.4-1986 描述。它也被 ISO 646:1991 描述(带有货币符号的本地化)。完整的 ASCII 集在表下面中给出,作为前 128 个元素。可以用 ASCII 中的字符充分书写的语言包括英语、夏威夷语、印度尼西亚语、斯瓦希里语和一些美洲原住民语言。
大多数非 EBCDIC 字符集都是 ASCII 的超集。也就是说,整数 0-127 的含义与 ASCII 中的含义相同。但整数 128 及以上是特定于字符集的。
许多字符集完全适合 8 位,使用 ASCII 作为 0-127,同时指定 128-255 的含义,并且不使用超过 255 的任何内容。因此,这些是单字节(或者如果你愿意,可以称为八位字节)字符集。其中一个重要的字符集是 ISO 8859-1 字符集(因为 Unicode 是它的超集)。
ISO 8859-$n 是国际标准化组织 (ISO) 的一系列字符代码集,每个代码集都向 ASCII 集添加了通常在各种语言中发现的字符,其中许多语言基于罗马字母或拉丁字母。大多数代码集用于欧洲语言,但也有一些代码集用于阿拉伯语、希腊语、希伯来语和泰语。网上有很多关于这些代码集的参考资料。
ASCII 的一个特殊的 8 位扩展,包括重音和锐音拉丁字符。可以使用 ISO 8859-1 的语言包括所有由 ASCII 涵盖的语言,以及南非荷兰语、阿尔巴尼亚语、巴斯克语、加泰罗尼亚语、丹麦语、法罗语、芬兰语、挪威语、葡萄牙语、西班牙语和瑞典语。荷兰语也涵盖在内,尽管没有 ij 连字。法语也涵盖在内,但没有 oe 连字。德语可以使用 ISO 8859-1,但必须不使用德式引号。此字符集基于 ASCII 的西欧扩展,在万维网工作中经常遇到。在 IBM 字符代码集识别术语中,ISO 8859-1 也称为 CCSID 819(有时也称为 0819 或 00819)。
扩展二进制编码十进制交换码指的是一大批单字节和多字节编码字符集,它们与 ASCII 和 ISO 8859-1 非常不同,并且彼此之间也略有不同;它们通常运行在主机计算机上。EBCDIC 编码源于霍勒瑞斯穿孔卡片编码的 8 位字节扩展,这些编码早于 ASCII 出现。卡片上的布局使得高位被设置为大小写字母 [a-z]
和 [A-Z]
,但在每个拉丁字母范围内都有间隙,在 下面的 表格中可以看到。这些间隙会导致复杂情况。
一些 IBM EBCDIC 字符集可能以字符代码集识别号(CCSID 号)或代码页号来识别。
Perl 可以编译在运行以下三种常用 EBCDIC 字符集的平台上。
在 IBM EBCDIC 字符代码集中,有 13 个字符通常映射到不同的整数值。这些字符被称为 13 个“变体”字符,它们是
\ [ ] { } ^ ~ ! # | $ @ `
当 Perl 为某个平台编译时,它会查看所有这些字符,以猜测该平台使用哪个 EBCDIC 字符集,并相应地调整自身以适应该平台。如果该平台使用的字符集不是 Perl 知道的三个字符集之一,Perl 可能会编译失败,或者错误地且静默地选择其中一个。
换行符 (LF) 实际上是第 14 个变体字符,Perl 也会检查它。
字符代码集 ID 0037 是 ASCII 加 Latin-1 字符(即 ISO 8859-1)到 EBCDIC 集的映射。0037 用于运行在 AS/400 计算机上的 OS/400 操作系统的北美英语语言环境中。CCSID 0037 在 236 个地方与 ISO 8859-1 不同;换句话说,它们只在 20 个代码点值上达成一致。
字符代码集 ID 1047 也是 ASCII 加 Latin-1 字符(即 ISO 8859-1)到 EBCDIC 集的映射。1047 用于 OS/390 或 z/OS 的 Unix 系统服务以及 VM/ESA 的 OpenEdition。CCSID 1047 在八个地方与 CCSID 0037 不同,在 236 个地方与 ISO 8859-1 不同。
西门子 BS2000 系统上使用的 EBCDIC 代码页与 1047 和 0037 不同。它在下面被标识为 POSIX-BC 集。与 0037 和 1047 一样,它在 20 个代码点值上与 ISO 8859-1 相同。
在 Unicode 术语中,代码点是指分配给字符的数字:例如,在 EBCDIC 中,字符“A”通常分配数字 193。在 Unicode 中,字符“A”分配数字 65。ASCII 和 Latin-1 (ISO 8859-1) 中的所有代码点在 Unicode 中具有相同的含义。所有三个识别的 EBCDIC 代码集都有 256 个代码点,并且在每个代码集中,所有 256 个代码点都映射到等效的 Latin1 代码点。显然,“A”将映射到“A”,“B”=>“B”,“%”=>“%”,等等,对于 Latin1 和这些代码页中的所有可打印字符都是如此。
事实证明,EBCDIC 几乎与 ASCII/Latin1 C0 控制和 DELETE 控制完全等效。(C0 控制是指其 ASCII 代码点为 0..0x1F 的那些控制;例如 TAB、ACK、BEL 等。)在这些 ASCII/EBCDIC 控制之间建立了映射。在 ASCII 平台上的 C1 控制和剩余的 EBCDIC 控制之间没有如此精确的映射。所做的是将这些控制(主要是任意地)映射到另一个字符集中一些原本不匹配的字符。如今,这些字符在 EBCDIC 中很少使用,并且它们的名称已被删除,没有引起太多抱怨。例如,EO(八个一)EBCDIC 控制(由八个 1 位组成 = 0xFF)映射到 C1 APC 控制(0x9F),并且您不能使用“EO”这个名称。
EBCDIC 控制提供三种可能的行终止符:CR (0x0D)、LF (0x25) 和 NL (0x15)。在 ASCII 平台上,符号“NL”和“LF”指的是同一个字符,但在严格的 EBCDIC 术语中,它们是不同的字符。EBCDIC NL 映射到称为“NEL”(“下一行”)的 C1 控制字符(这里映射很有意义,因此并非随意)。在一些 EBCDIC 平台上,这个 NL 或 NEL 是典型的行终止符。z/OS 和 BS2000 就是这样。在这些平台上,C 编译器会交换 LF 和 NEL 代码点,因此"\n"
为 0x15,并指代 NL。Perl 也这样做;您可以在下面的代码表中看到。这使得事情通常“正常工作”,您甚至不必意识到存在交换。
UTF 代表“Unicode 转换格式”。UTF-8 是 Unicode 编码为 8 位字节块序列的一种方式,它基于 ASCII 和 Latin-1。表示 Unicode 代码点的所需序列长度取决于该代码点的序数,较大的数字需要更多字节。UTF-EBCDIC 类似于 UTF-8,但基于 EBCDIC。它们足够相似,以至于在非正式使用中,这两个术语经常混淆,并使用“UTF-8”来表示 ASCII 平台上的 UTF-8 和 EBCDIC 平台上的 UTF-EBCDIC。
您可能会看到“不变”字符或代码点这个术语。这仅仅意味着字符在 UTF-8(或 UTF-EBCDIC)中编码时与未编码时具有相同的数值和表示。(请注意,这与上面提到的“13 个变体字符”的概念截然不同。谨慎的文字会使用“UTF-8 不变”而不是仅仅“不变”,但大多数情况下您只会看到“不变”。)例如,“A”的序数值在大多数 EBCDIC 代码页中为 193,在 UTF-EBCDIC 中编码时也为 193。所有 UTF-8(或 UTF-EBCDIC)变体代码点在 UTF-8(或 UTF-EBCDIC)中编码时至少占用两个字节;根据定义,UTF-8(或 UTF-EBCDIC)不变代码点无论是在 UTF-8(或 UTF-EBCDIC)中编码还是未编码,都恰好占用一个字节。(现在您明白为什么人们通常在也指代“UTF-EBCDIC”时只说“UTF-8”。在本文档的其余部分,我们也大多会非正式地使用它。)在 ASCII UTF-8 中,对应于最低 128 个序数(0 - 127:ASCII 字符)的代码点是不变的。在 UTF-EBCDIC 中,有 160 个不变字符。(如果您关心,EBCDIC 不变字符是那些具有 ASCII 等效字符的字符,以及那些对应于 C1 控制字符(在 ASCII 平台上为 128 - 159)的字符。)
以 UTF-EBCDIC 编码的字符串可能比以 UTF-8 编码的字符串更长(很少更短)。Perl 扩展了 UTF-8 和 UTF-EBCDIC,以便它们可以编码超过 Unicode 最大值 U+10FFFF 的代码点。这两种扩展都旨在允许编码任何适合 64 位字的代码点。
UTF-EBCDIC 由 Unicode 技术报告 #16 (通常简称为 TR16) 定义。它基于 CCSID 1047 定义,不考虑其他代码页的差异。这使得在运行不同代码页的计算机之间轻松交换文本成为可能,但如果没有进行调整,它将无法在其他代码页上的 Perl 中使用。
这种不可用性的原因是 Perl 的一个基本假设,即它在解析和词法分析时关心的字符,无论文本是否为 UTF-8 编码,都应该是相同的。例如,Perl 期望字符 "["
具有相同的表示形式,无论包含它的字符串(或程序文本)是否为 UTF-8 编码。为了确保这一点,Perl 将 UTF-EBCDIC 适配到特定的代码页,以便它期望的所有 UTF-8 不变字符实际上都是 UTF-8 不变的。这意味着在运行 Perl 的 UTF-EBCDIC 版本的计算机上生成的文本必须经过转换才能被运行其他版本的计算机理解。
TR16 隐含了一种方法来扩展 UTF-EBCDIC 以编码高达 2 ** 31 - 1
的点。Perl 使用这种方法来处理高达 2 ** 30 - 1
的代码点,但对于更大的代码点使用不兼容的方法,以使其能够处理比其他方法更大的代码点。
从 Perl 5.8 开始,您可以使用标准模块 Encode 将 EBCDIC 转换为 Latin-1 代码点。Encode 了解比 Perl 目前可以编译运行的更多 EBCDIC 字符集。
use Encode 'from_to';
my %ebcdic = ( 176 => 'cp37', 95 => 'cp1047', 106 => 'posix-bc' );
# $a is in EBCDIC code points
from_to($a, $ebcdic{ord '^'}, 'latin1');
# $a is ISO 8859-1 code points
以及从 Latin-1 代码点转换为 EBCDIC 代码点
use Encode 'from_to';
my %ebcdic = ( 176 => 'cp37', 95 => 'cp1047', 106 => 'posix-bc' );
# $a is ISO 8859-1 code points
from_to($a, 'latin1', $ebcdic{ord '^'});
# $a is in EBCDIC code points
对于 I/O 操作,建议您使用 PerlIO 的自动转换功能,请参阅 perluniintro。
从 5.8 版本开始,Perl 使用 PerlIO I/O 库。这使您能够为每个 IO 通道使用不同的编码。例如,您可以使用
use Encode;
open($f, ">:encoding(ascii)", "test.ascii");
print $f "Hello World!\n";
open($f, ">:encoding(cp37)", "test.ebcdic");
print $f "Hello World!\n";
open($f, ">:encoding(latin1)", "test.latin1");
print $f "Hello World!\n";
open($f, ">:encoding(utf8)", "test.utf8");
print $f "Hello World!\n";
获取四个文件,它们分别包含 ASCII、CP 0037 EBCDIC、ISO 8859-1 (Latin-1)(在本例中与 ASCII 相同,因为只打印了 ASCII 字符)和 UTF-EBCDIC(在本例中与普通 EBCDIC 相同,因为只打印了 EBCDIC 和 UTF-EBCDIC 之间没有区别的字符)中的 "Hello World!\n"。有关详细信息,请参阅 Encode::PerlIO 的文档。
由于 PerlIO 层在内部使用原始 IO(字节),因此完全忽略了文件系统类型(ASCII 或 EBCDIC)等因素。
以下表格列出了 ASCII 和 Latin 1 有序集,包括子集:C0 控制字符 (0..31)、ASCII 图形字符 (32..7e)、删除字符 (7f)、C1 控制字符 (80..9f) 和 Latin-1(也称为 ISO 8859-1)(a0..ff)。在表格中,Latin 1 对 ASCII 的扩展名称已使用大致对应于Unicode 标准,版本 6.1 的字符名称进行标记,但所有情况下都进行了替换,例如s/LATIN//
和 s/VULGAR//
;某些情况下为
;某些情况下为s/CAPITAL LETTER//
。控制字符使用其 Unicode 6.2 缩写列出。0037 和 1047 集之间的差异用s/SMALL LETTER ([A-Z])/\l$1/
**
标记。1047 和 POSIX-BC 集之间的差异用##.
标记。所有列出的ord()
数字均为十进制。如果您想查看此表格的八进制值列表,请运行表格(即此文档的 pod 源文本,因为此配方可能不适用于 pod2_other_format 转换)通过
perl -ne 'if(/(.{29})(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/)' \
-e '{printf("%s%-5.03o%-5.03o%-5.03o%.03o\n",$1,$2,$3,$4,$5)}' \
perlebcdic.pod
如果您想保留 UTF-x 代码点,那么在脚本形式中,您可能需要编写
open(FH,"<perlebcdic.pod") or die "Could not open perlebcdic.pod: $!";
while (<FH>) {
if (/(.{29})(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\.?(\d*)
\s+(\d+)\.?(\d*)/x)
{
if ($7 ne '' && $9 ne '') {
printf(
"%s%-5.03o%-5.03o%-5.03o%-5.03o%-3o.%-5o%-3o.%.03o\n",
$1,$2,$3,$4,$5,$6,$7,$8,$9);
}
elsif ($7 ne '') {
printf("%s%-5.03o%-5.03o%-5.03o%-5.03o%-3o.%-5o%.03o\n",
$1,$2,$3,$4,$5,$6,$7,$8);
}
else {
printf("%s%-5.03o%-5.03o%-5.03o%-5.03o%-5.03o%.03o\n",
$1,$2,$3,$4,$5,$6,$8);
}
}
}
如果您想查看此表格的十六进制值列表,请运行表格通过
perl -ne 'if(/(.{29})(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/)' \
-e '{printf("%s%-5.02X%-5.02X%-5.02X%.02X\n",$1,$2,$3,$4,$5)}' \
perlebcdic.pod
或者,为了保留十六进制的 UTF-x 代码点
open(FH,"<perlebcdic.pod") or die "Could not open perlebcdic.pod: $!";
while (<FH>) {
if (/(.{29})(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\.?(\d*)
\s+(\d+)\.?(\d*)/x)
{
if ($7 ne '' && $9 ne '') {
printf(
"%s%-5.02X%-5.02X%-5.02X%-5.02X%-2X.%-6.02X%02X.%02X\n",
$1,$2,$3,$4,$5,$6,$7,$8,$9);
}
elsif ($7 ne '') {
printf("%s%-5.02X%-5.02X%-5.02X%-5.02X%-2X.%-6.02X%02X\n",
$1,$2,$3,$4,$5,$6,$7,$8);
}
else {
printf("%s%-5.02X%-5.02X%-5.02X%-5.02X%-5.02X%02X\n",
$1,$2,$3,$4,$5,$6,$8);
}
}
}
ISO
8859-1 POS- CCSID
CCSID CCSID CCSID IX- 1047
chr 0819 0037 1047 BC UTF-8 UTF-EBCDIC
---------------------------------------------------------------------
<NUL> 0 0 0 0 0 0
<SOH> 1 1 1 1 1 1
<STX> 2 2 2 2 2 2
<ETX> 3 3 3 3 3 3
<EOT> 4 55 55 55 4 55
<ENQ> 5 45 45 45 5 45
<ACK> 6 46 46 46 6 46
<BEL> 7 47 47 47 7 47
<BS> 8 22 22 22 8 22
<HT> 9 5 5 5 9 5
<LF> 10 37 21 21 10 21 **
<VT> 11 11 11 11 11 11
<FF> 12 12 12 12 12 12
<CR> 13 13 13 13 13 13
<SO> 14 14 14 14 14 14
<SI> 15 15 15 15 15 15
<DLE> 16 16 16 16 16 16
<DC1> 17 17 17 17 17 17
<DC2> 18 18 18 18 18 18
<DC3> 19 19 19 19 19 19
<DC4> 20 60 60 60 20 60
<NAK> 21 61 61 61 21 61
<SYN> 22 50 50 50 22 50
<ETB> 23 38 38 38 23 38
<CAN> 24 24 24 24 24 24
<EOM> 25 25 25 25 25 25
<SUB> 26 63 63 63 26 63
<ESC> 27 39 39 39 27 39
<FS> 28 28 28 28 28 28
<GS> 29 29 29 29 29 29
<RS> 30 30 30 30 30 30
<US> 31 31 31 31 31 31
<SPACE> 32 64 64 64 32 64
! 33 90 90 90 33 90
" 34 127 127 127 34 127
# 35 123 123 123 35 123
$ 36 91 91 91 36 91
% 37 108 108 108 37 108
& 38 80 80 80 38 80
' 39 125 125 125 39 125
( 40 77 77 77 40 77
) 41 93 93 93 41 93
* 42 92 92 92 42 92
+ 43 78 78 78 43 78
, 44 107 107 107 44 107
- 45 96 96 96 45 96
. 46 75 75 75 46 75
/ 47 97 97 97 47 97
0 48 240 240 240 48 240
1 49 241 241 241 49 241
2 50 242 242 242 50 242
3 51 243 243 243 51 243
4 52 244 244 244 52 244
5 53 245 245 245 53 245
6 54 246 246 246 54 246
7 55 247 247 247 55 247
8 56 248 248 248 56 248
9 57 249 249 249 57 249
: 58 122 122 122 58 122
; 59 94 94 94 59 94
< 60 76 76 76 60 76
= 61 126 126 126 61 126
> 62 110 110 110 62 110
? 63 111 111 111 63 111
@ 64 124 124 124 64 124
A 65 193 193 193 65 193
B 66 194 194 194 66 194
C 67 195 195 195 67 195
D 68 196 196 196 68 196
E 69 197 197 197 69 197
F 70 198 198 198 70 198
G 71 199 199 199 71 199
H 72 200 200 200 72 200
I 73 201 201 201 73 201
J 74 209 209 209 74 209
K 75 210 210 210 75 210
L 76 211 211 211 76 211
M 77 212 212 212 77 212
N 78 213 213 213 78 213
O 79 214 214 214 79 214
P 80 215 215 215 80 215
Q 81 216 216 216 81 216
R 82 217 217 217 82 217
S 83 226 226 226 83 226
T 84 227 227 227 84 227
U 85 228 228 228 85 228
V 86 229 229 229 86 229
W 87 230 230 230 87 230
X 88 231 231 231 88 231
Y 89 232 232 232 89 232
Z 90 233 233 233 90 233
[ 91 186 173 187 91 173 ** ##
\ 92 224 224 188 92 224 ##
] 93 187 189 189 93 189 **
^ 94 176 95 106 94 95 ** ##
_ 95 109 109 109 95 109
` 96 121 121 74 96 121 ##
a 97 129 129 129 97 129
b 98 130 130 130 98 130
c 99 131 131 131 99 131
d 100 132 132 132 100 132
e 101 133 133 133 101 133
f 102 134 134 134 102 134
g 103 135 135 135 103 135
h 104 136 136 136 104 136
i 105 137 137 137 105 137
j 106 145 145 145 106 145
k 107 146 146 146 107 146
l 108 147 147 147 108 147
m 109 148 148 148 109 148
n 110 149 149 149 110 149
o 111 150 150 150 111 150
p 112 151 151 151 112 151
q 113 152 152 152 113 152
r 114 153 153 153 114 153
s 115 162 162 162 115 162
t 116 163 163 163 116 163
u 117 164 164 164 117 164
v 118 165 165 165 118 165
w 119 166 166 166 119 166
x 120 167 167 167 120 167
y 121 168 168 168 121 168
z 122 169 169 169 122 169
{ 123 192 192 251 123 192 ##
| 124 79 79 79 124 79
} 125 208 208 253 125 208 ##
~ 126 161 161 255 126 161 ##
<DEL> 127 7 7 7 127 7
<PAD> 128 32 32 32 194.128 32
<HOP> 129 33 33 33 194.129 33
<BPH> 130 34 34 34 194.130 34
<NBH> 131 35 35 35 194.131 35
<IND> 132 36 36 36 194.132 36
<NEL> 133 21 37 37 194.133 37 **
<SSA> 134 6 6 6 194.134 6
<ESA> 135 23 23 23 194.135 23
<HTS> 136 40 40 40 194.136 40
<HTJ> 137 41 41 41 194.137 41
<VTS> 138 42 42 42 194.138 42
<PLD> 139 43 43 43 194.139 43
<PLU> 140 44 44 44 194.140 44
<RI> 141 9 9 9 194.141 9
<SS2> 142 10 10 10 194.142 10
<SS3> 143 27 27 27 194.143 27
<DCS> 144 48 48 48 194.144 48
<PU1> 145 49 49 49 194.145 49
<PU2> 146 26 26 26 194.146 26
<STS> 147 51 51 51 194.147 51
<CCH> 148 52 52 52 194.148 52
<MW> 149 53 53 53 194.149 53
<SPA> 150 54 54 54 194.150 54
<EPA> 151 8 8 8 194.151 8
<SOS> 152 56 56 56 194.152 56
<SGC> 153 57 57 57 194.153 57
<SCI> 154 58 58 58 194.154 58
<CSI> 155 59 59 59 194.155 59
<ST> 156 4 4 4 194.156 4
<OSC> 157 20 20 20 194.157 20
<PM> 158 62 62 62 194.158 62
<APC> 159 255 255 95 194.159 255 ##
<NON-BREAKING SPACE> 160 65 65 65 194.160 128.65
<INVERTED "!" > 161 170 170 170 194.161 128.66
<CENT SIGN> 162 74 74 176 194.162 128.67 ##
<POUND SIGN> 163 177 177 177 194.163 128.68
<CURRENCY SIGN> 164 159 159 159 194.164 128.69
<YEN SIGN> 165 178 178 178 194.165 128.70
<BROKEN BAR> 166 106 106 208 194.166 128.71 ##
<SECTION SIGN> 167 181 181 181 194.167 128.72
<DIAERESIS> 168 189 187 121 194.168 128.73 ** ##
<COPYRIGHT SIGN> 169 180 180 180 194.169 128.74
<FEMININE ORDINAL> 170 154 154 154 194.170 128.81
<LEFT POINTING GUILLEMET> 171 138 138 138 194.171 128.82
<NOT SIGN> 172 95 176 186 194.172 128.83 ** ##
<SOFT HYPHEN> 173 202 202 202 194.173 128.84
<REGISTERED TRADE MARK> 174 175 175 175 194.174 128.85
<MACRON> 175 188 188 161 194.175 128.86 ##
<DEGREE SIGN> 176 144 144 144 194.176 128.87
<PLUS-OR-MINUS SIGN> 177 143 143 143 194.177 128.88
<SUPERSCRIPT TWO> 178 234 234 234 194.178 128.89
<SUPERSCRIPT THREE> 179 250 250 250 194.179 128.98
<ACUTE ACCENT> 180 190 190 190 194.180 128.99
<MICRO SIGN> 181 160 160 160 194.181 128.100
<PARAGRAPH SIGN> 182 182 182 182 194.182 128.101
<MIDDLE DOT> 183 179 179 179 194.183 128.102
<CEDILLA> 184 157 157 157 194.184 128.103
<SUPERSCRIPT ONE> 185 218 218 218 194.185 128.104
<MASC. ORDINAL INDICATOR> 186 155 155 155 194.186 128.105
<RIGHT POINTING GUILLEMET> 187 139 139 139 194.187 128.106
<FRACTION ONE QUARTER> 188 183 183 183 194.188 128.112
<FRACTION ONE HALF> 189 184 184 184 194.189 128.113
<FRACTION THREE QUARTERS> 190 185 185 185 194.190 128.114
<INVERTED QUESTION MARK> 191 171 171 171 194.191 128.115
<A WITH GRAVE> 192 100 100 100 195.128 138.65
<A WITH ACUTE> 193 101 101 101 195.129 138.66
<A WITH CIRCUMFLEX> 194 98 98 98 195.130 138.67
<A WITH TILDE> 195 102 102 102 195.131 138.68
<A WITH DIAERESIS> 196 99 99 99 195.132 138.69
<A WITH RING ABOVE> 197 103 103 103 195.133 138.70
<CAPITAL LIGATURE AE> 198 158 158 158 195.134 138.71
<C WITH CEDILLA> 199 104 104 104 195.135 138.72
<E WITH GRAVE> 200 116 116 116 195.136 138.73
<E WITH ACUTE> 201 113 113 113 195.137 138.74
<E WITH CIRCUMFLEX> 202 114 114 114 195.138 138.81
<E WITH DIAERESIS> 203 115 115 115 195.139 138.82
<I WITH GRAVE> 204 120 120 120 195.140 138.83
<I WITH ACUTE> 205 117 117 117 195.141 138.84
<I WITH CIRCUMFLEX> 206 118 118 118 195.142 138.85
<I WITH DIAERESIS> 207 119 119 119 195.143 138.86
<CAPITAL LETTER ETH> 208 172 172 172 195.144 138.87
<N WITH TILDE> 209 105 105 105 195.145 138.88
<O WITH GRAVE> 210 237 237 237 195.146 138.89
<O WITH ACUTE> 211 238 238 238 195.147 138.98
<O WITH CIRCUMFLEX> 212 235 235 235 195.148 138.99
<O WITH TILDE> 213 239 239 239 195.149 138.100
<O WITH DIAERESIS> 214 236 236 236 195.150 138.101
<MULTIPLICATION SIGN> 215 191 191 191 195.151 138.102
<O WITH STROKE> 216 128 128 128 195.152 138.103
<U WITH GRAVE> 217 253 253 224 195.153 138.104 ##
<U WITH ACUTE> 218 254 254 254 195.154 138.105
<U WITH CIRCUMFLEX> 219 251 251 221 195.155 138.106 ##
<U WITH DIAERESIS> 220 252 252 252 195.156 138.112
<Y WITH ACUTE> 221 173 186 173 195.157 138.113 ** ##
<CAPITAL LETTER THORN> 222 174 174 174 195.158 138.114
<SMALL LETTER SHARP S> 223 89 89 89 195.159 138.115
<a WITH GRAVE> 224 68 68 68 195.160 139.65
<a WITH ACUTE> 225 69 69 69 195.161 139.66
<a WITH CIRCUMFLEX> 226 66 66 66 195.162 139.67
<a WITH TILDE> 227 70 70 70 195.163 139.68
<a WITH DIAERESIS> 228 67 67 67 195.164 139.69
<a WITH RING ABOVE> 229 71 71 71 195.165 139.70
<SMALL LIGATURE ae> 230 156 156 156 195.166 139.71
<c WITH CEDILLA> 231 72 72 72 195.167 139.72
<e WITH GRAVE> 232 84 84 84 195.168 139.73
<e WITH ACUTE> 233 81 81 81 195.169 139.74
<e WITH CIRCUMFLEX> 234 82 82 82 195.170 139.81
<e WITH DIAERESIS> 235 83 83 83 195.171 139.82
<i WITH GRAVE> 236 88 88 88 195.172 139.83
<i WITH ACUTE> 237 85 85 85 195.173 139.84
<i WITH CIRCUMFLEX> 238 86 86 86 195.174 139.85
<i WITH DIAERESIS> 239 87 87 87 195.175 139.86
<SMALL LETTER eth> 240 140 140 140 195.176 139.87
<n WITH TILDE> 241 73 73 73 195.177 139.88
<o WITH GRAVE> 242 205 205 205 195.178 139.89
<o WITH ACUTE> 243 206 206 206 195.179 139.98
<o WITH CIRCUMFLEX> 244 203 203 203 195.180 139.99
<o WITH TILDE> 245 207 207 207 195.181 139.100
<o WITH DIAERESIS> 246 204 204 204 195.182 139.101
<DIVISION SIGN> 247 225 225 225 195.183 139.102
<o WITH STROKE> 248 112 112 112 195.184 139.103
<u WITH GRAVE> 249 221 221 192 195.185 139.104 ##
<u WITH ACUTE> 250 222 222 222 195.186 139.105
<u WITH CIRCUMFLEX> 251 219 219 219 195.187 139.106
<u WITH DIAERESIS> 252 220 220 220 195.188 139.112
<y WITH ACUTE> 253 141 141 141 195.189 139.113
<SMALL LETTER thorn> 254 142 142 142 195.190 139.114
<y WITH DIAERESIS> 255 223 223 223 195.191 139.115
如果您想查看上述表格的 CCSID 0037 顺序而不是 ASCII + Latin-1 顺序,请运行表格通过
perl \
-ne 'if(/.{29}\d{1,3}\s{2,4}\d{1,3}\s{2,4}\d{1,3}\s{2,4}\d{1,3}/)'\
-e '{push(@l,$_)}' \
-e 'END{print map{$_->[0]}' \
-e ' sort{$a->[1] <=> $b->[1]}' \
-e ' map{[$_,substr($_,34,3)]}@l;}' perlebcdic.pod
如果您想查看 CCSID 1047 顺序,请将最后一行中的数字 34 更改为 39,如下所示
perl \
-ne 'if(/.{29}\d{1,3}\s{2,4}\d{1,3}\s{2,4}\d{1,3}\s{2,4}\d{1,3}/)'\
-e '{push(@l,$_)}' \
-e 'END{print map{$_->[0]}' \
-e ' sort{$a->[1] <=> $b->[1]}' \
-e ' map{[$_,substr($_,39,3)]}@l;}' perlebcdic.pod
如果您想查看 POSIX-BC 顺序,请将最后一行中的数字 34 更改为 44,如下所示
perl \
-ne 'if(/.{29}\d{1,3}\s{2,4}\d{1,3}\s{2,4}\d{1,3}\s{2,4}\d{1,3}/)'\
-e '{push(@l,$_)}' \
-e 'END{print map{$_->[0]}' \
-e ' sort{$a->[1] <=> $b->[1]}' \
-e ' map{[$_,substr($_,44,3)]}@l;}' perlebcdic.pod
自从本文档首次编写以来,使用十六进制表示法来表示代码点的约定越来越普遍。要使用此方法来处理这些配方并进行排序,需要一个多步骤的过程,因此,为了方便起见,这里提供了上面表格的重新排序版本,按代码页 1047 顺序排序,并使用十六进制表示法。
ISO
8859-1 POS- CCSID
CCSID CCSID CCSID IX- 1047
chr 0819 0037 1047 BC UTF-8 UTF-EBCDIC
---------------------------------------------------------------------
<NUL> 00 00 00 00 00 00
<SOH> 01 01 01 01 01 01
<STX> 02 02 02 02 02 02
<ETX> 03 03 03 03 03 03
<ST> 9C 04 04 04 C2.9C 04
<HT> 09 05 05 05 09 05
<SSA> 86 06 06 06 C2.86 06
<DEL> 7F 07 07 07 7F 07
<EPA> 97 08 08 08 C2.97 08
<RI> 8D 09 09 09 C2.8D 09
<SS2> 8E 0A 0A 0A C2.8E 0A
<VT> 0B 0B 0B 0B 0B 0B
<FF> 0C 0C 0C 0C 0C 0C
<CR> 0D 0D 0D 0D 0D 0D
<SO> 0E 0E 0E 0E 0E 0E
<SI> 0F 0F 0F 0F 0F 0F
<DLE> 10 10 10 10 10 10
<DC1> 11 11 11 11 11 11
<DC2> 12 12 12 12 12 12
<DC3> 13 13 13 13 13 13
<OSC> 9D 14 14 14 C2.9D 14
<LF> 0A 25 15 15 0A 15 **
<BS> 08 16 16 16 08 16
<ESA> 87 17 17 17 C2.87 17
<CAN> 18 18 18 18 18 18
<EOM> 19 19 19 19 19 19
<PU2> 92 1A 1A 1A C2.92 1A
<SS3> 8F 1B 1B 1B C2.8F 1B
<FS> 1C 1C 1C 1C 1C 1C
<GS> 1D 1D 1D 1D 1D 1D
<RS> 1E 1E 1E 1E 1E 1E
<US> 1F 1F 1F 1F 1F 1F
<PAD> 80 20 20 20 C2.80 20
<HOP> 81 21 21 21 C2.81 21
<BPH> 82 22 22 22 C2.82 22
<NBH> 83 23 23 23 C2.83 23
<IND> 84 24 24 24 C2.84 24
<NEL> 85 15 25 25 C2.85 25 **
<ETB> 17 26 26 26 17 26
<ESC> 1B 27 27 27 1B 27
<HTS> 88 28 28 28 C2.88 28
<HTJ> 89 29 29 29 C2.89 29
<VTS> 8A 2A 2A 2A C2.8A 2A
<PLD> 8B 2B 2B 2B C2.8B 2B
<PLU> 8C 2C 2C 2C C2.8C 2C
<ENQ> 05 2D 2D 2D 05 2D
<ACK> 06 2E 2E 2E 06 2E
<BEL> 07 2F 2F 2F 07 2F
<DCS> 90 30 30 30 C2.90 30
<PU1> 91 31 31 31 C2.91 31
<SYN> 16 32 32 32 16 32
<STS> 93 33 33 33 C2.93 33
<CCH> 94 34 34 34 C2.94 34
<MW> 95 35 35 35 C2.95 35
<SPA> 96 36 36 36 C2.96 36
<EOT> 04 37 37 37 04 37
<SOS> 98 38 38 38 C2.98 38
<SGC> 99 39 39 39 C2.99 39
<SCI> 9A 3A 3A 3A C2.9A 3A
<CSI> 9B 3B 3B 3B C2.9B 3B
<DC4> 14 3C 3C 3C 14 3C
<NAK> 15 3D 3D 3D 15 3D
<PM> 9E 3E 3E 3E C2.9E 3E
<SUB> 1A 3F 3F 3F 1A 3F
<SPACE> 20 40 40 40 20 40
<NON-BREAKING SPACE> A0 41 41 41 C2.A0 80.41
<a WITH CIRCUMFLEX> E2 42 42 42 C3.A2 8B.43
<a WITH DIAERESIS> E4 43 43 43 C3.A4 8B.45
<a WITH GRAVE> E0 44 44 44 C3.A0 8B.41
<a WITH ACUTE> E1 45 45 45 C3.A1 8B.42
<a WITH TILDE> E3 46 46 46 C3.A3 8B.44
<a WITH RING ABOVE> E5 47 47 47 C3.A5 8B.46
<c WITH CEDILLA> E7 48 48 48 C3.A7 8B.48
<n WITH TILDE> F1 49 49 49 C3.B1 8B.58
<CENT SIGN> A2 4A 4A B0 C2.A2 80.43 ##
. 2E 4B 4B 4B 2E 4B
< 3C 4C 4C 4C 3C 4C
( 28 4D 4D 4D 28 4D
+ 2B 4E 4E 4E 2B 4E
| 7C 4F 4F 4F 7C 4F
& 26 50 50 50 26 50
<e WITH ACUTE> E9 51 51 51 C3.A9 8B.4A
<e WITH CIRCUMFLEX> EA 52 52 52 C3.AA 8B.51
<e WITH DIAERESIS> EB 53 53 53 C3.AB 8B.52
<e WITH GRAVE> E8 54 54 54 C3.A8 8B.49
<i WITH ACUTE> ED 55 55 55 C3.AD 8B.54
<i WITH CIRCUMFLEX> EE 56 56 56 C3.AE 8B.55
<i WITH DIAERESIS> EF 57 57 57 C3.AF 8B.56
<i WITH GRAVE> EC 58 58 58 C3.AC 8B.53
<SMALL LETTER SHARP S> DF 59 59 59 C3.9F 8A.73
! 21 5A 5A 5A 21 5A
$ 24 5B 5B 5B 24 5B
* 2A 5C 5C 5C 2A 5C
) 29 5D 5D 5D 29 5D
; 3B 5E 5E 5E 3B 5E
^ 5E B0 5F 6A 5E 5F ** ##
- 2D 60 60 60 2D 60
/ 2F 61 61 61 2F 61
<A WITH CIRCUMFLEX> C2 62 62 62 C3.82 8A.43
<A WITH DIAERESIS> C4 63 63 63 C3.84 8A.45
<A WITH GRAVE> C0 64 64 64 C3.80 8A.41
<A WITH ACUTE> C1 65 65 65 C3.81 8A.42
<A WITH TILDE> C3 66 66 66 C3.83 8A.44
<A WITH RING ABOVE> C5 67 67 67 C3.85 8A.46
<C WITH CEDILLA> C7 68 68 68 C3.87 8A.48
<N WITH TILDE> D1 69 69 69 C3.91 8A.58
<BROKEN BAR> A6 6A 6A D0 C2.A6 80.47 ##
, 2C 6B 6B 6B 2C 6B
% 25 6C 6C 6C 25 6C
_ 5F 6D 6D 6D 5F 6D
> 3E 6E 6E 6E 3E 6E
? 3F 6F 6F 6F 3F 6F
<o WITH STROKE> F8 70 70 70 C3.B8 8B.67
<E WITH ACUTE> C9 71 71 71 C3.89 8A.4A
<E WITH CIRCUMFLEX> CA 72 72 72 C3.8A 8A.51
<E WITH DIAERESIS> CB 73 73 73 C3.8B 8A.52
<E WITH GRAVE> C8 74 74 74 C3.88 8A.49
<I WITH ACUTE> CD 75 75 75 C3.8D 8A.54
<I WITH CIRCUMFLEX> CE 76 76 76 C3.8E 8A.55
<I WITH DIAERESIS> CF 77 77 77 C3.8F 8A.56
<I WITH GRAVE> CC 78 78 78 C3.8C 8A.53
` 60 79 79 4A 60 79 ##
: 3A 7A 7A 7A 3A 7A
# 23 7B 7B 7B 23 7B
@ 40 7C 7C 7C 40 7C
' 27 7D 7D 7D 27 7D
= 3D 7E 7E 7E 3D 7E
" 22 7F 7F 7F 22 7F
<O WITH STROKE> D8 80 80 80 C3.98 8A.67
a 61 81 81 81 61 81
b 62 82 82 82 62 82
c 63 83 83 83 63 83
d 64 84 84 84 64 84
e 65 85 85 85 65 85
f 66 86 86 86 66 86
g 67 87 87 87 67 87
h 68 88 88 88 68 88
i 69 89 89 89 69 89
<LEFT POINTING GUILLEMET> AB 8A 8A 8A C2.AB 80.52
<RIGHT POINTING GUILLEMET> BB 8B 8B 8B C2.BB 80.6A
<SMALL LETTER eth> F0 8C 8C 8C C3.B0 8B.57
<y WITH ACUTE> FD 8D 8D 8D C3.BD 8B.71
<SMALL LETTER thorn> FE 8E 8E 8E C3.BE 8B.72
<PLUS-OR-MINUS SIGN> B1 8F 8F 8F C2.B1 80.58
<DEGREE SIGN> B0 90 90 90 C2.B0 80.57
j 6A 91 91 91 6A 91
k 6B 92 92 92 6B 92
l 6C 93 93 93 6C 93
m 6D 94 94 94 6D 94
n 6E 95 95 95 6E 95
o 6F 96 96 96 6F 96
p 70 97 97 97 70 97
q 71 98 98 98 71 98
r 72 99 99 99 72 99
<FEMININE ORDINAL> AA 9A 9A 9A C2.AA 80.51
<MASC. ORDINAL INDICATOR> BA 9B 9B 9B C2.BA 80.69
<SMALL LIGATURE ae> E6 9C 9C 9C C3.A6 8B.47
<CEDILLA> B8 9D 9D 9D C2.B8 80.67
<CAPITAL LIGATURE AE> C6 9E 9E 9E C3.86 8A.47
<CURRENCY SIGN> A4 9F 9F 9F C2.A4 80.45
<MICRO SIGN> B5 A0 A0 A0 C2.B5 80.64
~ 7E A1 A1 FF 7E A1 ##
s 73 A2 A2 A2 73 A2
t 74 A3 A3 A3 74 A3
u 75 A4 A4 A4 75 A4
v 76 A5 A5 A5 76 A5
w 77 A6 A6 A6 77 A6
x 78 A7 A7 A7 78 A7
y 79 A8 A8 A8 79 A8
z 7A A9 A9 A9 7A A9
<INVERTED "!" > A1 AA AA AA C2.A1 80.42
<INVERTED QUESTION MARK> BF AB AB AB C2.BF 80.73
<CAPITAL LETTER ETH> D0 AC AC AC C3.90 8A.57
[ 5B BA AD BB 5B AD ** ##
<CAPITAL LETTER THORN> DE AE AE AE C3.9E 8A.72
<REGISTERED TRADE MARK> AE AF AF AF C2.AE 80.55
<NOT SIGN> AC 5F B0 BA C2.AC 80.53 ** ##
<POUND SIGN> A3 B1 B1 B1 C2.A3 80.44
<YEN SIGN> A5 B2 B2 B2 C2.A5 80.46
<MIDDLE DOT> B7 B3 B3 B3 C2.B7 80.66
<COPYRIGHT SIGN> A9 B4 B4 B4 C2.A9 80.4A
<SECTION SIGN> A7 B5 B5 B5 C2.A7 80.48
<PARAGRAPH SIGN> B6 B6 B6 B6 C2.B6 80.65
<FRACTION ONE QUARTER> BC B7 B7 B7 C2.BC 80.70
<FRACTION ONE HALF> BD B8 B8 B8 C2.BD 80.71
<FRACTION THREE QUARTERS> BE B9 B9 B9 C2.BE 80.72
<Y WITH ACUTE> DD AD BA AD C3.9D 8A.71 ** ##
<DIAERESIS> A8 BD BB 79 C2.A8 80.49 ** ##
<MACRON> AF BC BC A1 C2.AF 80.56 ##
] 5D BB BD BD 5D BD **
<ACUTE ACCENT> B4 BE BE BE C2.B4 80.63
<MULTIPLICATION SIGN> D7 BF BF BF C3.97 8A.66
{ 7B C0 C0 FB 7B C0 ##
A 41 C1 C1 C1 41 C1
B 42 C2 C2 C2 42 C2
C 43 C3 C3 C3 43 C3
D 44 C4 C4 C4 44 C4
E 45 C5 C5 C5 45 C5
F 46 C6 C6 C6 46 C6
G 47 C7 C7 C7 47 C7
H 48 C8 C8 C8 48 C8
I 49 C9 C9 C9 49 C9
<SOFT HYPHEN> AD CA CA CA C2.AD 80.54
<o WITH CIRCUMFLEX> F4 CB CB CB C3.B4 8B.63
<o WITH DIAERESIS> F6 CC CC CC C3.B6 8B.65
<o WITH GRAVE> F2 CD CD CD C3.B2 8B.59
<o WITH ACUTE> F3 CE CE CE C3.B3 8B.62
<o WITH TILDE> F5 CF CF CF C3.B5 8B.64
} 7D D0 D0 FD 7D D0 ##
J 4A D1 D1 D1 4A D1
K 4B D2 D2 D2 4B D2
L 4C D3 D3 D3 4C D3
M 4D D4 D4 D4 4D D4
N 4E D5 D5 D5 4E D5
O 4F D6 D6 D6 4F D6
P 50 D7 D7 D7 50 D7
Q 51 D8 D8 D8 51 D8
R 52 D9 D9 D9 52 D9
<SUPERSCRIPT ONE> B9 DA DA DA C2.B9 80.68
<u WITH CIRCUMFLEX> FB DB DB DB C3.BB 8B.6A
<u WITH DIAERESIS> FC DC DC DC C3.BC 8B.70
<u WITH GRAVE> F9 DD DD C0 C3.B9 8B.68 ##
<u WITH ACUTE> FA DE DE DE C3.BA 8B.69
<y WITH DIAERESIS> FF DF DF DF C3.BF 8B.73
\ 5C E0 E0 BC 5C E0 ##
<DIVISION SIGN> F7 E1 E1 E1 C3.B7 8B.66
S 53 E2 E2 E2 53 E2
T 54 E3 E3 E3 54 E3
U 55 E4 E4 E4 55 E4
V 56 E5 E5 E5 56 E5
W 57 E6 E6 E6 57 E6
X 58 E7 E7 E7 58 E7
Y 59 E8 E8 E8 59 E8
Z 5A E9 E9 E9 5A E9
<SUPERSCRIPT TWO> B2 EA EA EA C2.B2 80.59
<O WITH CIRCUMFLEX> D4 EB EB EB C3.94 8A.63
<O WITH DIAERESIS> D6 EC EC EC C3.96 8A.65
<O WITH GRAVE> D2 ED ED ED C3.92 8A.59
<O WITH ACUTE> D3 EE EE EE C3.93 8A.62
<O WITH TILDE> D5 EF EF EF C3.95 8A.64
0 30 F0 F0 F0 30 F0
1 31 F1 F1 F1 31 F1
2 32 F2 F2 F2 32 F2
3 33 F3 F3 F3 33 F3
4 34 F4 F4 F4 34 F4
5 35 F5 F5 F5 35 F5
6 36 F6 F6 F6 36 F6
7 37 F7 F7 F7 37 F7
8 38 F8 F8 F8 38 F8
9 39 F9 F9 F9 39 F9
<SUPERSCRIPT THREE> B3 FA FA FA C2.B3 80.62
<U WITH CIRCUMFLEX> DB FB FB DD C3.9B 8A.6A ##
<U WITH DIAERESIS> DC FC FC FC C3.9C 8A.70
<U WITH GRAVE> D9 FD FD E0 C3.99 8A.68 ##
<U WITH ACUTE> DA FE FE FE C3.9A 8A.69
<APC> 9F FF FF 5F C2.9F FF ##
可以确定您正在使用的字符集。但首先,您需要非常确定您确实需要这样做。如果您不必测试字符集并根据情况执行不同的操作,您的代码将更简单,并且可能同样可移植。实际上,只有很少情况下,编写可移植到所有字符集的直线代码并不容易。有关如何可移植地指定字符,请参见 perluniintro 中的“Unicode 和 EBCDIC”。
但是,在某些情况下,您可能需要知道正在使用的字符集。一个可能的例子是在性能至关重要的内部循环中进行 排序。
要确定您是在 ASCII 下运行还是在 EBCDIC 下运行,您可以使用 ord()
或 chr()
的返回值来测试一个或多个字符值。例如
$is_ascii = "A" eq chr(65);
$is_ebcdic = "A" eq chr(193);
$is_ascii = ord("A") == 65;
$is_ebcdic = ord("A") == 193;
区分 EBCDIC 代码页的必要性更小,但要这样做,请尝试查看一个或多个在它们之间不同的字符。
$is_ascii = ord('[') == 91;
$is_ebcdic_37 = ord('[') == 186;
$is_ebcdic_1047 = ord('[') == 173;
$is_ebcdic_POSIX_BC = ord('[') == 187;
但是,编写如下测试是不明智的
$is_ascii = "\r" ne chr(13); # WRONG
$is_ascii = "\n" ne chr(10); # ILL ADVISED
显然,第一个测试将无法区分大多数 ASCII 平台与 CCSID 0037、1047 或 POSIX-BC EBCDIC 平台,因为在所有这些编码字符集中,"\r" eq chr(13)
。但也要注意,因为在旧的 Macintosh(这是一个 ASCII 平台)上,"\n"
是 chr(13)
,而 "\r"
是 chr(10)
,所以第二个 $is_ascii
测试在那里会导致问题。
要确定 perl 是否在 EBCDIC 代码页下构建,您可以使用 Config 模块,如下所示
use Config;
$is_ebcdic = $Config{'ebcdic'} eq 'define';
utf8::unicode_to_native()
和 utf8::native_to_unicode()
这些函数接受一种编码中的输入数字代码点,并返回其在另一种编码中的等效值。
请参见 utf8。
为了将字符串从一种字符集转换为另一种字符集,只需要一个简单的数字列表(如上表右列所示)以及 Perl 的 tr///
运算符。表中的数据按 ASCII/Latin1 顺序排列,因此 EBCDIC 列提供了易于使用的 ASCII/Latin1 到 EBCDIC 操作,这些操作也很容易反转。
例如,要将 ASCII/Latin1 转换为代码页 037,请从配方 2 的输出中获取第二列数字的输出(修改为添加 "\"
字符),并在 tr///
中使用它,如下所示
$cp_037 =
'\x00\x01\x02\x03\x37\x2D\x2E\x2F\x16\x05\x25\x0B\x0C\x0D\x0E\x0F' .
'\x10\x11\x12\x13\x3C\x3D\x32\x26\x18\x19\x3F\x27\x1C\x1D\x1E\x1F' .
'\x40\x5A\x7F\x7B\x5B\x6C\x50\x7D\x4D\x5D\x5C\x4E\x6B\x60\x4B\x61' .
'\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\x7A\x5E\x4C\x7E\x6E\x6F' .
'\x7C\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xD1\xD2\xD3\xD4\xD5\xD6' .
'\xD7\xD8\xD9\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xBA\xE0\xBB\xB0\x6D' .
'\x79\x81\x82\x83\x84\x85\x86\x87\x88\x89\x91\x92\x93\x94\x95\x96' .
'\x97\x98\x99\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xC0\x4F\xD0\xA1\x07' .
'\x20\x21\x22\x23\x24\x15\x06\x17\x28\x29\x2A\x2B\x2C\x09\x0A\x1B' .
'\x30\x31\x1A\x33\x34\x35\x36\x08\x38\x39\x3A\x3B\x04\x14\x3E\xFF' .
'\x41\xAA\x4A\xB1\x9F\xB2\x6A\xB5\xBD\xB4\x9A\x8A\x5F\xCA\xAF\xBC' .
'\x90\x8F\xEA\xFA\xBE\xA0\xB6\xB3\x9D\xDA\x9B\x8B\xB7\xB8\xB9\xAB' .
'\x64\x65\x62\x66\x63\x67\x9E\x68\x74\x71\x72\x73\x78\x75\x76\x77' .
'\xAC\x69\xED\xEE\xEB\xEF\xEC\xBF\x80\xFD\xFE\xFB\xFC\xAD\xAE\x59' .
'\x44\x45\x42\x46\x43\x47\x9C\x48\x54\x51\x52\x53\x58\x55\x56\x57' .
'\x8C\x49\xCD\xCE\xCB\xCF\xCC\xE1\x70\xDD\xDE\xDB\xDC\x8D\x8E\xDF';
my $ebcdic_string = $ascii_string;
eval '$ebcdic_string =~ tr/\000-\377/' . $cp_037 . '/';
要从 EBCDIC 037 转换为 ASCII,只需反转 tr///
参数的顺序,如下所示
my $ascii_string = $ebcdic_string;
eval '$ascii_string =~ tr/' . $cp_037 . '/\000-\377/';
类似地,可以从配方 2 的第三列数字输出中获取 $cp_1047
表。配方 2 的第四列数字输出可以提供一个适合转码的 $cp_posix_bc
表。
如果您想查看反向表,则首先需要按配方 4、5 或 6 中的所需数字列进行排序,然后获取第一列数字的输出。
XPG 可操作性通常意味着 shell 或 C 库中存在 iconv 实用程序。请参阅您系统的文档以获取有关 iconv 的信息。
在 OS/390 或 z/OS 上,请参阅 iconv(1) 手册页。从 Perl 中调用 iconv
shell 实用程序的一种方法是
# OS/390 or z/OS example
$ascii_data = `echo '$ebcdic_data'| iconv -f IBM-1047 -t ISO8859-1`
或反向映射
# OS/390 or z/OS example
$ebcdic_data = `echo '$ascii_data'| iconv -f ISO8859-1 -t IBM-1047`
有关其他基于 Perl 的转换选项,请参阅 CPAN 上的 Convert::*
模块。
OS/390 和 z/OS C 运行时库提供 _atoe()
和 _etoa()
函数。
..
范围运算符在 EBCDIC 平台上会谨慎地处理某些字符范围。例如,以下数组在 EBCDIC 平台或 ASCII 平台上都将有 26 个元素
@alphabet = ('A'..'Z'); # $#alphabet == 25
当在 EBCDIC 平台上运行的 Perl 程序中对字符串或字符数据进行位运算(如 & ^ |)时,其返回的结果可能与在 ASCII 平台上运行时不同。以下是一个改编自 perlop 中的示例
# EBCDIC-based examples
print "j p \n" ^ " a h"; # prints "JAPH\n"
print "JA" | " ph\n"; # prints "japh\n"
print "JAPH\nJunk" & "\277\277\277\277\277"; # prints "japh\n";
print 'p N$' ^ " E<H\n"; # prints "Perl\n";
ASCII 表中 32 个 C0 控制字符的一个有趣特性是,它们可以在 Perl 中“字面地”被构造为控制字符,例如:(chr(0)
eq \c@
)> (chr(1)
eq \cA
)>,等等。EBCDIC 平台上的 Perl 已经被移植以将 \c@
映射到 chr(0)
,将 \cA
映射到 chr(1)
,等等,但最终得到的字符取决于你使用的代码页。下表使用控制字符的标准缩写。POSIX-BC 和 1047 集在这整个范围内是相同的,并且只在 21 个十进制位置与 0037 集不同。请注意,行终止符字符可以在 ASCII 平台上由 \cJ
生成,但在 1047 或 POSIX-BC 平台上由 \cU
生成,并且不能在 0037 平台上作为 "\c.letter."
控制字符生成。还要注意,\c\
不能是字符串或正则表达式的最后一个元素,因为它会吸收终止符。但是 \c\X
是一个 FILE SEPARATOR
与 X 的连接,对于所有 X 都是如此。ASCII 上的异常值 \c?
,它产生一个非 C0 控制 DEL
,在 EBCDIC 上产生异常值控制 APC
,它是唯一不在连续控制块中的一个。请注意,一个微妙之处是,ASCII 平台上的 \c?
是一个 ASCII 字符,而在 EBCDIC 平台上它不等于任何 ASCII 字符。
chr ord 8859-1 0037 1047 && POSIX-BC
-----------------------------------------------------------------------
\c@ 0 <NUL> <NUL> <NUL>
\cA 1 <SOH> <SOH> <SOH>
\cB 2 <STX> <STX> <STX>
\cC 3 <ETX> <ETX> <ETX>
\cD 4 <EOT> <ST> <ST>
\cE 5 <ENQ> <HT> <HT>
\cF 6 <ACK> <SSA> <SSA>
\cG 7 <BEL> <DEL> <DEL>
\cH 8 <BS> <EPA> <EPA>
\cI 9 <HT> <RI> <RI>
\cJ 10 <LF> <SS2> <SS2>
\cK 11 <VT> <VT> <VT>
\cL 12 <FF> <FF> <FF>
\cM 13 <CR> <CR> <CR>
\cN 14 <SO> <SO> <SO>
\cO 15 <SI> <SI> <SI>
\cP 16 <DLE> <DLE> <DLE>
\cQ 17 <DC1> <DC1> <DC1>
\cR 18 <DC2> <DC2> <DC2>
\cS 19 <DC3> <DC3> <DC3>
\cT 20 <DC4> <OSC> <OSC>
\cU 21 <NAK> <NEL> <LF> **
\cV 22 <SYN> <BS> <BS>
\cW 23 <ETB> <ESA> <ESA>
\cX 24 <CAN> <CAN> <CAN>
\cY 25 <EOM> <EOM> <EOM>
\cZ 26 <SUB> <PU2> <PU2>
\c[ 27 <ESC> <SS3> <SS3>
\c\X 28 <FS>X <FS>X <FS>X
\c] 29 <GS> <GS> <GS>
\c^ 30 <RS> <RS> <RS>
\c_ 31 <US> <US> <US>
\c? * <DEL> <APC> <APC>
*
注意:\c?
在 ASCII 平台上映射到序数 127 (DEL
),但由于序数 127 在 EBCDIC 机器上不是控制字符,所以 \c?
在它们上映射到 APC
,在 0037 和 1047 中是 255,在 POSIX-BC 中是 95。
chr()
chr()
必须在 EBCDIC 平台上接收一个 EBCDIC 代码编号参数才能产生所需的字符返回值。例如
$CAPITAL_LETTER_A = chr(193);
ord()
ord()
在 EBCDIC 平台上将返回 EBCDIC 代码编号值。例如
$the_number_193 = ord("A");
pack()
pack()
的 "c"
和 "C"
模板取决于字符集编码。EBCDIC 上的用法示例包括
$foo = pack("CCCC",193,194,195,196);
# $foo eq "ABCD"
$foo = pack("C4",193,194,195,196);
# same thing
$foo = pack("ccxxcc",193,194,195,196);
# $foo eq "AB\0\0CD"
"U"
模板已被移植到所有平台上表示“Unicode”,因此
pack("U", 65) eq 'A'
在所有平台上都是真的。如果你想要低 256 的本机代码点,请使用 "W"
模板。这意味着等价关系
pack("W", ord($character)) eq $character
unpack("W", $character) == ord $character
将成立。
print()
对于传递给 print
的包含 ASCII 编码的标量和字符串,必须小心。这种情况经常发生在 CGI 脚本编写中 MIME 类型头部的输出中。例如,许多 Perl 编程指南建议使用类似于以下内容的代码:
print "Content-type:\ttext/html\015\012\015\012";
# this may be wrong on EBCDIC
你可以改为编写
print "Content-type:\ttext/html\r\n\r\n"; # OK for DGW et al
并使其可移植地工作。
这是因为在这种情况下,从 EBCDIC 到 ASCII 的转换是由 Web 服务器完成的。有关更多详细信息,请参阅您的 Web 服务器文档。
printf()
在 EBCDIC 平台上执行时,可以将字符转换为数字反之亦然的格式将不同于其 ASCII 对应格式。示例包括
printf("%c%c%c",193,194,195); # prints ABC
sort()
EBCDIC 排序结果可能与 ASCII 排序结果不同,尤其是在混合大小写字符串的情况下。这将在下面更详细地讨论。
sprintf()
请参阅上面关于"printf()"
的讨论。使用 sprintf 的一个示例是
$CAPITAL_LETTER_A = sprintf("%c",193);
unpack()
请参阅上面关于"pack()"
的讨论。
请注意,可以通过在 Unicode 数字中指定内容并使用转换函数来编写这些内容的可移植代码
printf("%c",utf8::unicode_to_native(65)); # prints A on all
# platforms
print utf8::native_to_unicode(ord("A")); # Likewise, prints 65
请参阅"perluniintro 中的 Unicode 和 EBCDIC" 和"CONVERSIONS" 以获取其他选项。
您可以像在 ASCII 平台上的人一样编写正则表达式。但请记住,使用八进制或十六进制表示法来指定特定代码点将为您提供 EBCDIC 代码页本机映射到的字符。(这也适用于所有双引号字符串。)如果您想编写可移植代码,只需在您使用\x{...}
的任何地方使用\N{U+...}
表示法,并且根本不要使用八进制表示法。
从 Perl v5.22 开始,这适用于方括号字符类中的范围。例如,如果您说qr/[\N{U+20}-\N{U+7F}]/
,则表示字符\N{U+20}
、\N{U+21}
、...、\N{U+7F}
。此范围是 ASCII 字符集包含的所有可打印字符。
在 v5.22 之前,您无法以可移植的方式指定任何范围,除了(从 Perl v5.5.3 开始)[A-Z]
和 [a-z]
范围的所有子集都被专门编码为不拾取间隙字符。例如,诸如 "ô"(o WITH CIRCUMFLEX
)之类的字符位于 "I" 和 "J" 之间,不会被正则表达式范围/[H-K]/
匹配。但如果范围端点中的任何一个明确是数字(并且两者都不是由\N{U+...}
指定的),则会匹配间隙字符
/[\x89-\x91]/
将匹配\x8e
,即使\x89
是 "i" 并且\x91
是 "j",而\x8e
是一个间隙字符,从字母的角度来看。
另一个需要注意的结构是在正则表达式中不恰当地使用十六进制(除非使用\N{U+...}
)或八进制常量。考虑以下一组替换
sub is_c0 {
my $char = substr(shift,0,1);
$char =~ /[\000-\037]/;
}
sub is_print_ascii {
my $char = substr(shift,0,1);
$char =~ /[\040-\176]/;
}
sub is_delete {
my $char = substr(shift,0,1);
$char eq "\177";
}
sub is_c1 {
my $char = substr(shift,0,1);
$char =~ /[\200-\237]/;
}
sub is_latin_1 { # But not ASCII; not C1
my $char = substr(shift,0,1);
$char =~ /[\240-\377]/;
}
这些仅在 ASCII 平台上有效。从 Perl v5.22 开始,只需将八进制常量更改为等效的\N{U+...}
值即可使它们可移植
sub is_c0 {
my $char = substr(shift,0,1);
$char =~ /[\N{U+00}-\N{U+1F}]/;
}
sub is_print_ascii {
my $char = substr(shift,0,1);
$char =~ /[\N{U+20}-\N{U+7E}]/;
}
sub is_delete {
my $char = substr(shift,0,1);
$char eq "\N{U+7F}";
}
sub is_c1 {
my $char = substr(shift,0,1);
$char =~ /[\N{U+80}-\N{U+9F}]/;
}
sub is_latin_1 { # But not ASCII; not C1
my $char = substr(shift,0,1);
$char =~ /[\N{U+A0}-\N{U+FF}]/;
}
以下是一些可移植的替代写法
sub Is_c0 {
my $char = substr(shift,0,1);
return $char =~ /[[:cntrl:]]/a && ! Is_delete($char);
# Alternatively:
# return $char =~ /[[:cntrl:]]/
# && $char =~ /[[:ascii:]]/
# && ! Is_delete($char);
}
sub Is_print_ascii {
my $char = substr(shift,0,1);
return $char =~ /[[:print:]]/a;
# Alternatively:
# return $char =~ /[[:print:]]/ && $char =~ /[[:ascii:]]/;
# Or
# return $char
# =~ /[ !"\#\$%&'()*+,\-.\/0-9:;<=>?\@A-Z[\\\]^_`a-z{|}~]/;
}
sub Is_delete {
my $char = substr(shift,0,1);
return utf8::native_to_unicode(ord $char) == 0x7F;
}
sub Is_c1 {
use feature 'unicode_strings';
my $char = substr(shift,0,1);
return $char =~ /[[:cntrl:]]/ && $char !~ /[[:ascii:]]/;
}
sub Is_latin_1 { # But not ASCII; not C1
use feature 'unicode_strings';
my $char = substr(shift,0,1);
return ord($char) < 256
&& $char !~ /[[:ascii:]]/
&& $char !~ /[[:cntrl:]]/;
}
另一种写Is_latin_1()
的方法是显式地使用该范围内的字符
sub Is_latin_1 {
my $char = substr(shift,0,1);
$char =~ /[ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ]
[ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ]/x;
}
虽然这种形式可能会在网络传输(由于存在 8 位字符)或非 ISO-Latin 字符集中遇到问题。但它确实允许Is_c1
被重写,以便它在没有'unicode_strings'
的 Perl(早于 v5.14)上工作
sub Is_latin_1 { # But not ASCII; not C1
my $char = substr(shift,0,1);
return ord($char) < 256
&& $char !~ /[[:ascii:]]/
&& ! Is_latin1($char);
}
大多数套接字编程假设网络字节序中的 ASCII 字符编码。例外情况包括在主机 Web 服务器下编写 CGI 脚本,其中服务器可能会为您处理转换。大多数主机 Web 服务器将 EBCDIC 数据转换为 ISO-8859-1 或 Unicode 以进行输出。
基于 ASCII 的字符集和 EBCDIC 字符集之间的一个主要区别是字符在本地排序时的相对位置。最重要的是大小写字母、数字和下划线("_"
)。在 ASCII 平台上,本地排序顺序是数字在字母之前,字母在下划线之前,下划线在小写字母之前。在 EBCDIC 上,下划线排在首位,然后是小写字母,然后是大写字母,最后是数字。如果在基于 ASCII 的平台上排序,医生的两位字母缩写将排在驱动的两位字母缩写之前;也就是说
@sorted = sort(qw(Dr. dr.)); # @sorted holds ('Dr.','dr.') on ASCII,
# but ('dr.','Dr.') on EBCDIC
EBCDIC 中小写字母排序顺序的特性甚至延续到了 Latin 1 EBCDIC 页面,例如 0037 和 1047。例如,在 ASCII 平台上,"Ë" (E WITH DIAERESIS
, 203) 排在 "ë" (e WITH DIAERESIS
, 235) 之前,但在 EBCDIC 平台上,后者 (83) 排在前者 (115) 之前。(敏锐的读者会注意到,"ß" (SMALL LETTER SHARP S
) 的大写形式只是 "SS",而 "ÿ" (小写 y WITH DIAERESIS
) 和 "µ" (MICRO SIGN
) 的大写形式不在 0..255 范围内,而是在 Unicode 中,在一个支持 Unicode 的 Perl 中)。
排序顺序会导致在 ASCII 平台和 EBCDIC 平台上获得的结果之间存在差异。以下是一些关于如何处理这些差异的建议。
这是计算成本最低的策略。它可能需要一些用户教育。
这是完全通用的,但也是计算成本最高的策略。选择其中一个字符集,并在每次排序比较时转换为该字符集。以下是一个将数据转换为 ASCII 排序顺序的完整示例
sub native_to_uni($) {
my $string = shift;
# Saves time on an ASCII platform
return $string if ord 'A' == 65;
my $output = "";
for my $i (0 .. length($string) - 1) {
$output
.= chr(utf8::native_to_unicode(ord(substr($string, $i, 1))));
}
# Preserve utf8ness of input onto the output, even if it didn't need
# to be utf8
utf8::upgrade($output) if utf8::is_utf8($string);
return $output;
}
sub ascii_order { # Sort helper
return native_to_uni($a) cmp native_to_uni($b);
}
sort ascii_order @list;
如果您不关心数字和下划线在排序中的位置,您可以执行以下操作
sub case_insensitive_order { # Sort helper
return lc($a) cmp lc($b)
}
sort case_insensitive_order @list;
如果性能是一个问题,并且您不关心输出是否与输入的大小写相同,请使用 tr///
将数据转换为数据中使用最多的那个大小写。如果数据主要是大写非 Latin-1 字符,则应用 tr/[a-z]/[A-Z]/
,然后 sort()
。如果数据主要是小写非 Latin-1 字符,则在排序之前应用 tr/[A-Z]/[a-z]/
。如果数据主要是大写并包含 Latin-1 字符,则应用
tr/[a-z]/[A-Z]/;
tr/[àáâãäåæçèéêëìíîïðñòóôõöøùúûüýþ]/[ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ/;
s/ß/SS/g;
然后 sort()
。如果您有选择,最好将数据转换为小写,以避免两个 Latin-1 字符的大写形式不在 Latin-1 范围内的麻烦:"ÿ" (小写 y WITH DIAERESIS
) 和 "µ" (MICRO SIGN
)。如果您确实需要将数据转换为大写,您可以这样做;在支持 Unicode 的 Perl 中,您可以执行
tr/ÿ/\x{178}/;
tr/µ/\x{39C}/;
此策略可以使用网络连接。因此,它将是计算成本很高的。
有多种方法可以使用字符集内部映射来转换数据,这些方法服务于各种目的。排序在上一节中进行了讨论,接下来将讨论一些其他更流行的映射技术。
请注意,一些 URL 中包含十六进制 ASCII 码点,以解决字符或协议限制问题。例如,波浪号 (~) 不在所有键盘上,因此以下形式的 URL
http://www.pvhp.com/~pvhp/
也可以表示为以下两种形式之一:
http://www.pvhp.com/%7Epvhp/
http://www.pvhp.com/%7epvhp/
其中 7E 是 "~" 的十六进制 ASCII 码点。以下是在任何 EBCDIC 代码页中解码此类 URL 的示例
$url = 'http://www.pvhp.com/%7Epvhp/';
$url =~ s/%([0-9a-fA-F]{2})/
pack("c",utf8::unicode_to_native(hex($1)))/xge;
相反,以下是在任何 EBCDIC 代码页中编码此类 URL 的部分解决方案
$url = 'http://www.pvhp.com/~pvhp/';
# The following regular expression does not address the
# mappings for: ('.' => '%2E', '/' => '%2F', ':' => '%3A')
$url =~ s/([\t "#%&\(\),;<=>\?\@\[\\\]^`{|}~])/
sprintf("%%%02X",utf8::native_to_unicode(ord($1)))/xge;
其中更完整的解决方案将 URL 分解为组件,并仅对适当的部分应用完整的 s/// 替换。
u
模板用于 pack()
或 unpack()
将 EBCDIC 数据呈现为与其 ASCII 对应物等效的 EBCDIC 字符。例如,以下代码将在 ASCII 或 EBCDIC 计算机上打印 "Yes indeed\n"
$all_byte_chrs = '';
for (0..255) { $all_byte_chrs .= chr($_); }
$uuencode_byte_chrs = pack('u', $all_byte_chrs);
($uu = <<'ENDOFHEREDOC') =~ s/^\s*//gm;
M``$"`P0%!@<("0H+#`T.#Q`1$A,4%187&!D:&QP='A\@(2(C)"4F)R@I*BLL
M+2XO,#$R,S0U-C<X.3H[/#T^/T!!0D-$149'2$E*2TQ-3D]045)35%565UA9
M6EM<75Y?8&%B8V1E9F=H:6IK;&UN;W!Q<G-T=79W>'EZ>WQ]?G^`@8*#A(6&
MAXB)BHN,C8Z/D)&2DY25EI>8F9J;G)V>GZ"AHJ.DI::GJ*FJJZRMKJ^PL;*S
MM+6VM[BYNKN\O;Z_P,'"P\3%QL?(R<K+S,W.S]#1TM/4U=;7V-G:V]S=WM_@
?X>+CY.7FY^CIZNOL[>[O\/'R\_3U]O?X^?K[_/W^_P``
ENDOFHEREDOC
if ($uuencode_byte_chrs eq $uu) {
print "Yes ";
}
$uudecode_byte_chrs = unpack('u', $uuencode_byte_chrs);
if ($uudecode_byte_chrs eq $all_byte_chrs) {
print "indeed\n";
}
以下是一个非常简陋的 uudecoder,它将在 EBCDIC 上运行
#!/usr/local/bin/perl
$_ = <> until ($mode,$file) = /^begin\s*(\d*)\s*(\S*)/;
open(OUT, "> $file") if $file ne "";
while(<>) {
last if /^end/;
next if /[a-z]/;
next unless int((((utf8::native_to_unicode(ord()) - 32 ) & 077)
+ 2) / 3)
== int(length() / 4);
print OUT unpack("u", $_);
}
close(OUT);
chmod oct($mode), $file;
在 ASCII 编码的平台上,可以使用以下代码去除可打印集之外的字符
# This QP encoder works on ASCII only
$qp_string =~ s/([=\x00-\x1F\x80-\xFF])/
sprintf("=%02X",ord($1))/xge;
从 Perl v5.22 开始,这可以轻松地更改为在 ASCII 和 EBCDIC 平台上都可移植地工作。
# This QP encoder works on both ASCII and EBCDIC
$qp_string =~ s/([=\N{U+00}-\N{U+1F}\N{U+80}-\N{U+FF}])/
sprintf("=%02X",ord($1))/xge;
对于早期的 Perl 版本,在 ASCII 和 EBCDIC 平台上都工作的 QP 编码器看起来类似于以下代码
$delete = utf8::unicode_to_native(ord("\x7F"));
$qp_string =~
s/([^[:print:]$delete])/
sprintf("=%02X",utf8::native_to_unicode(ord($1)))/xage;
(尽管在生产代码中,替换可能在 EBCDIC 分支中使用函数调用完成,而在 ASCII 分支中单独完成,而无需身份映射的开销;在 Perl v5.22 中,身份映射被优化掉了,因此没有开销,但上面的替代方案更简单,并且在 v5.22 中也可用)。
可以使用以下代码解码此类 QP 字符串
# This QP decoder is limited to ASCII only
$string =~ s/=([[:xdigit:][[:xdigit:])/chr hex $1/ge;
$string =~ s/=[\n\r]+$//;
而在 ASCII 和 EBCDIC 平台上都工作的 QP 解码器看起来类似于以下代码
$string =~ s/=([[:xdigit:][:xdigit:]])/
chr utf8::native_to_unicode(hex $1)/xge;
$string =~ s/=[\n\r]+$//;
将字母表移动一个或多个字符以进行加密的做法可以追溯到几千年前,并且在盖乌斯·尤利乌斯·凯撒的《高卢战记》中明确详细说明。单个字母表移位有时被称为旋转,移位量在字符串 'rot' 或 "rot$n" 之后以数字 $n 表示。Rot0 和 rot26 将指定 26 个字母的拉丁字母表的英文版本上的身份映射。Rot13 具有有趣的特性,即交替的后续调用是身份映射(因此 rot13 在 26 个字母旋转组中是它自己的非平凡逆)。因此,以下代码是 rot13 编码器和解码器,它将在 ASCII 和 EBCDIC 平台上运行
#!/usr/local/bin/perl
while(<>){
tr/n-za-mN-ZA-M/a-zA-Z/;
print;
}
一行形式
perl -ne 'tr/n-za-mN-ZA-M/a-zA-Z/;print'
为了安全目的,Perl 在 ASCII 和 EBCDIC 平台上故意随机化哈希顺序。
相同文件翻译成 ASCII 和 EBCDIC 后,EBCDIC 校验和将不同。
即使在 EBCDIC 平台上,国际化 (I18N) 和本地化 (L10N) 也至少在原则上得到支持。具体细节取决于系统,并在下面的 "操作系统问题" 部分讨论。
Perl 使用 UTF-EBCDIC,一种多字节编码。在 v5.22 之前的 Perl 版本中,这方面可能存在各种错误。
旧版多字节 EBCDIC 代码页 XXX。
EBCDIC Perl 程序员可能需要关注一些系统相关问题。
PASE 环境是 OS/400 的运行时环境,可以在 OS/400 中运行为 PowerPC AIX 构建的可执行文件;请参阅 perlos400。PASE 基于 ASCII,而不是像 ILE 那样基于 EBCDIC。
XXX。
Perl 在 Unix 系统服务 (USS) 下运行。
sigaction
SA_SIGINFO
可能出现段错误。
chcp
chcp 作为 shell 实用程序支持,用于显示和更改用户的代码页。另请参阅 chcp(1)。
对于顺序数据集访问,请尝试
my @ds_records = `cat //DSNAME`;
或
my @ds_records = `cat //'HLQ.DSNAME'`;
另请参阅 CPAN 上的 OS390::Stdio 模块。
iconv
iconv 作为 shell 实用程序和 C RTL 例程都得到支持。另请参阅 iconv(1) 和 iconv(3) 手册页。
区域设置得到支持。当区域设置是另一个 EBCDIC 代码页时,可能会出现故障,该代码页在其他位置包含一些 代码页变体字符。
目前还没有真正的 UTF-8 区域设置,即使一些区域设置名称包含字符串 "UTF-8"。
有关区域设置的信息,请参阅 perllocale。L10N 文件位于 /usr/nls/locale 中。$Config{d_setlocale}
在 OS/390 或 z/OS 上为 'define'
。
XXX。
并非所有 shell 都允许将 perl 中的多个 -e
字符串参数正确地连接在一起,正如本文档中 0、2、4、5 和 6 中的食谱所暗示的那样。
Perl v5.22 和 5.24 附带的 CPAN 模块中存在大量测试失败。这些失败仅存在于并非主要由 Perl 5 移植者维护的模块中。其中一些是测试本身的失败:它们没有意识到在 EBCDIC 平台上获得不同的结果是正常的。而一些失败则是真正的错误。如果你编译并对 Perl 进行 make test
,则会跳过 /cpan
目录上的所有测试。
Encode 部分工作。
在早期的 Perl 版本中,当字节和字符数据连接在一起时,新的字符串有时是通过将字节字符串解码为 ISO 8859-1 (Latin-1) 创建的,即使旧的 Unicode 字符串使用 EBCDIC。
perllocale、perlfunc、perlunicode、utf8。
http://std.dkuug.dk/i18n/charmaps
https://www.unicode.org/reports/tr16/
https://www.sr-ix.com/Archive/CharCodeHist/index.html ASCII:美国信息交换标准代码 Tom Jennings,1999 年 9 月。
Unicode 标准,版本 3.0 Unicode 联盟,Lisa Moore 编,ISBN 0-201-61633-5,Addison Wesley 开发者出版社,2000 年 2 月。
CDRA:IBM - 字符数据表示体系结构 - 参考和注册,IBM SC09-2190-00,1996 年 12 月。
“字符集解密”,Andrea Vine,多语言计算与技术,第 10 卷第 4 期第 26 期,1999 年 8 月/9 月;ISSN 1523-0309;多语言计算公司,美国爱达荷州桑德波因特。
代码、密码和其他神秘和秘密通信 Fred B. Wrixon,ISBN 1-57912-040-7,黑狗与列文萨尔出版社,1998 年。
http://www.bobbemer.com/P-BIT.HTM IBM - EBCDIC 和 P 位;有史以来最大的计算机错误 Robert Bemer。
2001 年 4 月 15 日:将 UTF-8 和 UTF-EBCDIC 添加到主表中,pvhp。
Peter Prymmer [email protected] 于 1999 年和 2000 年编写了本文档,使用 CCSID 0819 和 0037,并得到了 Chris Leach 和 André Pirard [email protected] 以及 Thomas Dorner [email protected] 的 POSIX-BC 帮助。也感谢 Vickie Cooper、Philip Newton、William Raffloer 和 Joe Smith。本文档中使用的商标、注册商标、服务商标和注册服务商标均为其各自所有者的财产。
现在由 Perl5 Porters 维护。