【问题标题】:What do the non-printable characters in the Perl symbol table represent?Perl 符号表中不可打印的字符代表什么?
【发布时间】:2013-04-10 04:48:49
【问题描述】:

我刚刚了解到,在 Perl 中,给定模块的符号表存储在与模块名称匹配的散列中 - 例如,虚构模块 Foo::Bar 的符号表将是 %Foo::Bar。默认符号表存储在%main:: 中。出于好奇,我决定要查看%main:: 中的内容,因此遍历散列中的每个键/值对,边走边打印:

#! /usr/bin/perl

use v5.14;
use strict;
use warnings;

my $foo;
my $bar;
my %hash;

while( my ( $key, $value ) = each  %:: )  {
    say "Key: '$key' Value '$value'";
} 

输出如下所示:

Key: 'version::' Value '*main::version::'
Key: '/' Value '*main::/'
Key: '' Value '*main::'
Key: 'stderr' Value '*main::stderr'
Key: '_<perl.c' Value '*main::_<perl.c'
Key: ',' Value '*main::,'
Key: '2' Value '*main::2'
...

我期待看到 STDOUT 和 STDERR 文件句柄,也许还有 @INC 和 %ENV……我没想到看到的是非 ascii 字符……上面的代码块没有显示是输出的第三行实际上有一个表示不可打印字符的字形。

我运行脚本并按如下方式通过管道传输:

perl /tmp/asdf.pl | grep '[^[:print:]]' | while read line
do 
    echo $line
    od -c <<< $line
    echo
done

输出如下所示:

Key: '' Value '*main::'
0000000   K   e   y   :       ' 026   '       V   a   l   u   e       '
0000020   *   m   a   i   n   :   : 026   '  \n
0000032

Key: 'ARNING_BITS' Value '*main::ARNING_BITS'
0000000   K   e   y   :       ' 027   A   R   N   I   N   G   _   B   I
0000020   T   S   '       V   a   l   u   e       '   *   m   a   i   n
0000040   :   : 027   A   R   N   I   N   G   _   B   I   T   S   '  \n
0000060

Key: '' Value '*main::'
0000000   K   e   y   :       ' 022   '       V   a   l   u   e       '
0000020   *   m   a   i   n   :   : 022   '  \n
0000032

Key: 'E_TRIE_MAXBUF' Value '*main::E_TRIE_MAXBUF'
0000000   K   e   y   :       ' 022   E   _   T   R   I   E   _   M   A
0000020   X   B   U   F   '       V   a   l   u   e       '   *   m   a
0000040   i   n   :   : 022   E   _   T   R   I   E   _   M   A   X   B
0000060   U   F   '  \n
0000064

Key: ' Value '*main:'
0000000   K   e   y   :       '  \b   '       V   a   l   u   e       '
0000020   *   m   a   i   n   :   :  \b   '  \n
0000032

Key: '' Value '*main::'
0000000   K   e   y   :       ' 030   '       V   a   l   u   e       '
0000020   *   m   a   i   n   :   : 030   '  \n
0000032

那么,不可打印字符在 Perl 符号表中的作用是什么?它们的符号是什么?

【问题讨论】:

  • 我不知道,但看起来所有不可打印的键都具有相同的值,*main::
  • 实际上,这只是当我粘贴到 StackOverflow 时删除了控制字符的字形这一事实的产物。尝试运行我上面的代码,或者甚至更好的代码,包括 ilmari 对不可打印字符的翻译,你就会清楚符号表中的值是什么。
  • 哎呀,你是对的。我检查了键是否有不可打印的字符,但没有检查值!

标签: perl


【解决方案1】:

Guru 走在了正确的轨道上:具体来说,答案可以在perlvar 中找到,上面写着:

"Perl 变量名也可以是数字序列或单个标点符号或控制字符。这些名称都是为 Perl 保留的特殊用途;例如,全数字名称用于保存后向引用捕获的数据一个正则表达式匹配。Perl 对单控制字符名称有一种特殊的语法:它理解 ^X (caret X) 来表示 control-X 字符。例如,符号 $^W (dollar-sign caret W ) 是标量变量,其名称是单字符 control-W。这比在程序中键入文字 control-W 更好。

从 Perl 5.6 开始,Perl 变量名可以是以控制字符(或者更好的是,插入符号)开头的字母数字字符串。这些变量必须写成${^Foo}的形式;大括号不是可选的。 ${^Foo} 表示标量变量,其名称为 control-F 后跟两个 o。这些变量为 Perl 将来的特殊用途保留,以 ^_ 开头的变量除外(控制下划线或插入符号下划线)。任何以^_ 开头的控制字符名称都不会在 Perl 的任何未来版本中获得特殊含义;因此,这些名称可以在程序中安全地使用。但是,$^_ 本身是保留的。”

如果您想以可读的方式打印这些名称,您可以在代码中添加这样的一行:

$key = '^' . ($key ^ '@') if $key =~ /^[\0-\x1f]/;

如果$key 的第一个字符是控制字符,则将其替换为插入符号,后跟相应的字母(^A 用于控制-A,^B 用于控制-B,等等)。

【讨论】:

  • 感谢提供翻译代码;这实际上回答了问题中更神秘的部分之一,即 *main::\027ARNING_BITS,它变成了 *main::^WARNING_BITS。
  • $key =~ s/^([\0-\x1F])/'^'.($1 ^ '@')/e;怎么样
  • @Brad:当然,这完全一样。
  • 使用“@”字符进行异或运算是一种非常标准的方法吗?
  • @NateGlenn:相对标准,是的。它之所以起作用,是因为ASCII 字符编码的一个怪癖/功能,但是,控制字符的整个“control-X”表示法基于非常怪异.如果您愿意,可以将'@' 写为"\x40" 以使位模式更清晰。同样,与空格 ("\x20") 进行异或运算将切换 ASCII 字母的大小写。在过去,这是一个非常有用的设计功能,可以简化这些修饰键的实现。
【解决方案2】:

Perl 具有特殊的变量,例如 $"$,$/$\ 等。所有这些都是符号表的一部分,这就是您所看到的。此外,您应该也可以在符号表中看到@INC、%ENV。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-09
    • 2016-05-07
    • 1970-01-01
    • 2013-08-22
    • 2014-08-13
    • 1970-01-01
    • 2017-12-16
    • 2020-10-08
    相关资源
    最近更新 更多