内容

名称

charnames - 访问 Unicode 字符名称和命名字符序列;也定义字符名称

概要

use charnames ':full';
print "\N{GREEK SMALL LETTER SIGMA} is called sigma.\n";
print "\N{LATIN CAPITAL LETTER E WITH VERTICAL LINE BELOW}",
      " is an officially named sequence of two Unicode characters\n";

use charnames ':loose';
print "\N{Greek small-letter  sigma}",
       "can be used to ignore case, underscores, most blanks,"
       "and when you aren't sure if the official name has hyphens\n";

use charnames ':short';
print "\N{greek:Sigma} is an upper-case sigma.\n";

use charnames qw(cyrillic greek);
print "\N{sigma} is Greek sigma, and \N{be} is Cyrillic b.\n";

use utf8;
use charnames ":full", ":alias" => {
  e_ACUTE => "LATIN SMALL LETTER E WITH ACUTE",
  mychar => 0xE8000,  # Private use area
  "自転車に乗る人" => "BICYCLIST"
};
print "\N{e_ACUTE} is a small letter e with an acute.\n";
print "\N{mychar} allows me to name private use characters.\n";
print "And I can create synonyms in other languages,",
      " such as \N{自転車に乗る人} for "BICYCLIST (U+1F6B4)\n";

use charnames ();
print charnames::viacode(0x1234); # prints "ETHIOPIC SYLLABLE SEE"
printf "%04X", charnames::vianame("GOTHIC LETTER AHSA"); # prints
                                                         # "10330"
print charnames::vianame("LATIN CAPITAL LETTER A"); # prints 65 on
                                                    # ASCII platforms;
                                                    # 193 on EBCDIC
print charnames::string_vianame("LATIN CAPITAL LETTER A"); # prints "A"

描述

use charnames 编译指令用于访问 Unicode 字符和命名字符序列的名称,并允许您定义自己的字符和字符序列名称。

所有形式的编译指令都允许使用以下 3 个函数

从 Perl v5.16 开始,双引号字符串中出现的任何 \N{CHARNAME} 序列都会自动加载此模块,参数为 :full:short(如下所述),前提是它尚未使用不同的参数加载,以便将命名的 Unicode 字符编译到字符串中的位置。在 v5.16 之前,需要显式使用 use charnames 来启用此用法。(但是,在 v5.16 之前,表单 "use charnames ();" 不会启用 \N{CHARNAME}。)

请注意,\N{U+...}(其中 ... 是一个十六进制数字)也会将字符插入字符串中。它插入的字符是其 Unicode 代码点(序数值)等于该数字的字符。例如,"\N{U+263a}" 是 Unicode(白色背景,黑色前景)笑脸,等效于 "\N{WHITE SMILING FACE}"。另外请注意,当 ... 是一个数字(或用逗号分隔的数字对(参见 "perlreref 中的 QUANTIFIERS")时,\N{...} 可以表示正则表达式量词,而不是字符名称,并且与该 pragma 无关。

charnames pragma 支持参数 :full:loose:short、脚本名称和 自定义别名

如果存在 :full,则为了扩展 \N{CHARNAME},字符串 CHARNAME 首先会在标准 Unicode 字符名称列表中查找。

:loose:full 的变体,它允许 CHARNAME 的指定不太精确。详细信息请参见 "LOOSE MATCHES"

如果存在 :short,并且 CHARNAME 的形式为 SCRIPT:CNAME,则 CNAME 会在脚本 SCRIPT 中作为字母查找,如下一段所述。或者,如果 use charnames 与脚本名称参数一起使用,则对于 \N{CHARNAME},名称 CHARNAME 会在给定的脚本(按指定顺序)中作为字母查找。自定义别名可以覆盖这些,并在 "CUSTOM ALIASES" 中解释。

为了在给定的脚本 SCRIPTNAME 中查找 CHARNAME,该 pragma 会在标准 Unicode 名称表中查找以下名称:

SCRIPTNAME CAPITAL LETTER CHARNAME
SCRIPTNAME SMALL LETTER CHARNAME
SCRIPTNAME LETTER CHARNAME

如果 CHARNAME 全部为小写,则会忽略 CAPITAL 变体,否则会忽略 SMALL 变体,并且 CHARNAMESCRIPTNAME 都将转换为全大写以进行查找。除此之外,如果还指定了 :loose,则两者都遵循 松散 规则;否则严格遵循。

请注意,\N{...} 是编译时的;它是双引号字符串中使用的字符串常量的特殊形式;这意味着您不能在 \N{...} 中使用变量。如果您想要类似的运行时功能,请使用 charnames::string_vianame()

注意,从 Perl 5.18 开始,BELL 指的是 Unicode 字符 U+1F514,而不是传统的 U+0007。对于后者,请使用 ALERTBEL

如果 NAME 未知,则使用 \N{NAME} 会导致语法错误。

对于 \N{NAME},如果 use bytes 生效且输入名称是无法放入一个字节的字符的名称(即,其序数大于 255),则会发生致命错误。

否则,任何包含 \N{charname}\N{U+code point} 的字符串将自动应用 Unicode 规则(参见 "perlunicode 中的字节和字符语义")。

宽松匹配

通过指定 :loose,将选择 Unicode 的 宽松字符名称匹配 规则,而不是其他情况下使用的严格精确匹配。这意味着 CHARNAME 不必那么精确地指定。大小写无关紧要(除了上面提到的脚本),也不需要任何下划线,只有名称中单词开头或结尾的连字符才重要(有一个例外:U+1180 HANGUL JUNGSEONG O-E 中的连字符很重要)。此外,与连字符不相邻的空格也不重要。官方 Unicode 名称在使用连字符还是空格来分隔类似单词的单元方面变化很大,此选项允许您不必太在意。非中间连字符重要的原因是像 U+0F60 TIBETAN LETTER -A 和 U+0F68 TIBETAN LETTER A 这样的情况。这里的连字符很重要,它前面的空格也很重要,因此两者都必须包含在内。

:loose:full 慢 2 到 3 倍,但这种权衡可能对您来说是值得的。每次单独查找所需的时间非常短,并且结果会被缓存,因此速度差异只会出现在对许多不同拼写进行查找的程序中,而且可能只有在通过 vianame()string_vianame() 进行查找时才会出现,因为 \N{...} 查找是在编译时完成的。

别名

从 Unicode 6.1 和 Perl v5.16 开始,Unicode 定义了许多以前是 Perl 扩展的缩写和名称,以及一些 Perl 以前不接受的额外名称。这个列表太长了,这里无法全部列出,但您可以在 Unicode 网站上获取完整列表:http://www.unicode.org/Public/UNIDATA/NameAliases.txt.

早期版本的 Perl 接受了几乎所有 6.1 名称。这些名称在该 pod 的 v5.14 版本中得到了最广泛的记录:https://perldoc.perl5.cn/5.14.0/charnames.html#ALIASES.

自定义别名

您可以将自定义别名添加到标准 (:full) Unicode 命名约定中。别名会覆盖任何标准定义,因此,如果您足够扭曲,您可以将 "\N{LATIN CAPITAL LETTER A}" 更改为 "B" 等。

别名必须以字母字符开头。之后,每个别名可以包含任何组合的单词 (\w) 字符、空格 (U+0020)、连字符 (U+002D)、左括号 (U+0028) 和右括号 (U+0029)。最后两个字符不应该被允许出现在名称中,它们仅为了向后兼容而保留,并且可能会在 Perl 的未来版本中被弃用并删除,因此不要将它们用于新名称。(更准确地说,您指定的名称的第一个字符必须是与 \p{ID_Start}\p{Alphabetic}\p{Gc=Letter} 全部匹配的字符。这确保了它是一个任何合理的人都会认为是字母字符的字符。并且,与 \w 匹配的延续字符也必须与 \p{ID_Continue} 匹配。) 从 Perl v5.18 开始,任何满足上述条件的 Unicode 字符都可以使用;在此之前,只有 Latin1 范围内的字符是可接受的。

别名可以映射到官方 Unicode 字符名称(而不是松散匹配的名称)或数字代码点(序数)。后者对于将名称分配给 Unicode 私有使用区域中的代码点很有用,例如 U+E800 到 U+F8FF。数字代码点必须是非负整数,或以 "U+""0x" 开头的字符串,其余部分被视为十六进制整数。文字数字常量必须是无符号的;如果它以零开头或包含非十进制十六进制数字,它将被解释为十六进制;否则它将被解释为十进制。如果它以 "U+" 开头,它将被解释为 Unicode 代码点;否则它将被解释为本地代码点。(只有低于 256 的代码点在 Unicode 和本地代码点之间可能不同。) 因此 U+41 始终是拉丁字母 "A";但 0x41 在 EBCDIC 平台上可能是 "NO-BREAK SPACE"。

别名可以通过匿名哈希添加

use charnames ":alias" => {
    e_ACUTE => "LATIN SMALL LETTER E WITH ACUTE",
    mychar1 => 0xE8000,
    };
my $str = "\N{e_ACUTE}";

或者通过使用包含别名的文件添加

use charnames ":alias" => "pro";

这将尝试从 @INC 路径中读取 "unicore/pro_alias.pl"。此文件应以纯 Perl 返回一个列表

(
A_GRAVE         => "LATIN CAPITAL LETTER A WITH GRAVE",
A_CIRCUM        => "LATIN CAPITAL LETTER A WITH CIRCUMFLEX",
A_DIAERES       => "LATIN CAPITAL LETTER A WITH DIAERESIS",
A_TILDE         => "LATIN CAPITAL LETTER A WITH TILDE",
A_BREVE         => "LATIN CAPITAL LETTER A WITH BREVE",
A_RING          => "LATIN CAPITAL LETTER A WITH RING ABOVE",
A_MACRON        => "LATIN CAPITAL LETTER A WITH MACRON",
mychar2         => "U+E8001",
);

这两种方法都会自动将 ":full" 插入为第一个参数(如果没有其他参数给出),并且您也可以显式地给出 ":full",例如

use charnames ":full", ":alias" => "pro";

":loose" 对这些没有影响。输入名称必须完全匹配,使用 ":full" 规则。

此外,这两种方法目前只允许命名单个字符。要命名一系列字符,请使用 自定义翻译器(如下所述)。

charnames::string_vianame(name)

这是 \N{...} 的运行时等效项。name 可以是任何表达式,该表达式计算结果为 \N{...}:full 选项 下接受的名称 charnames。此外,相同作用域中控制 "use charnames" 的任何其他选项都适用,例如 :loose 或任何 脚本列表,:short 选项,或您可能已定义的 自定义别名

唯一的区别是 string_vianame 是运行时,而 \N{} 是编译时。您不能在 \N{} 中进行插值(因此 \N{$variable} 不起作用);如果输入名称未知,string_vianame 将返回 undef,而不是语法错误。

charnames::vianame(name)

这类似于 string_vianame。主要区别在于,在大多数情况下,vianame 返回一个序数代码点,而 string_vianame 返回一个字符串。例如,

printf "U+%04X", charnames::vianame("FOUR TEARDROP-SPOKED ASTERISK");

打印 "U+2722"。

这导致了另外两个区别。由于返回单个代码点,因此该函数无法处理命名字符序列,因为这些序列由多个字符组成(对于这些序列,它返回 undef。并且,代码点可以是任何字符的代码点,即使是那些在 use bytes 伪指令下不合法。

有关行为与上述描述不同的情况,请参阅 "BUGS"

charnames::viacode(code)

返回由数字代码指示的字符的完整名称。例如,

print charnames::viacode(0x2722);

打印“FOUR TEARDROP-SPOKED ASTERISK”。

返回的名称是代码点的“最佳”(定义如下)官方名称或别名(如果可用);否则是您为其定义的自定义别名(如果已定义);否则为 undef。这意味着您的别名只会在没有官方 Unicode 名称(或别名)的代码点(例如专用代码点)上返回。

如果您为代码点定义了多个名称,则无法确定将返回哪个名称。

如上所述,如果代码点没有已知名称,则该函数将返回 undef。在 Unicode 中,这些代码点的正确名称是空字符串,undef 字符串化为该字符串。(如果您请求的代码点超过了您未分配别名的合法 Unicode 最大值 U+10FFFF,您将获得 undef 以及警告。)

输入数字必须是非负整数,或者以 "U+""0x" 开头的字符串,其余部分被视为十六进制整数。文字数字常量必须是无符号的;如果它以零开头或包含非十进制十六进制数字,它将被解释为十六进制;否则它将被解释为十进制。如果它以 "U+" 开头,它将被解释为 Unicode 代码点;否则它将被解释为本机代码点。(只有低于 256 的代码点在 Unicode 和本机之间可能不同。)因此 U+41 始终是拉丁字母“A”;但 0x41 在 EBCDIC 平台上可能是“NO-BREAK SPACE”。

如上所述,在 "ALIASES" 中,Unicode 6.1 为某些代码点定义了额外的名称(同义词或别名),其中大多数已经作为 Perl 扩展可用。所有这些都被 \N{...} 和此模块中的其他函数接受,但 viacode 必须选择为给定输入代码点返回哪个名称,因此它返回“最佳”名称。要了解它是如何工作的,了解有关 Unicode 名称属性的更多信息将很有帮助。所有代码点实际上只有一个名称,该名称(从 Unicode 2.0 开始)在将字符分配给代码点后永远不会改变。但分配名称时确实出现过错误,例如,有时在发布标准时会发生文书错误,导致单词拼写错误,并且无法纠正这些错误。Name_Alias 属性最终被创建来处理这些情况。如果名称错误,将发布一个更正的同义词,使用 Name_Alias。viacode 将返回该更正的同义词作为代码点的“最佳”名称。(甚至有可能,尽管还没有发生,但更正本身需要更正,因此可以为该代码点创建另一个 Name_Alias;viacode 将返回最新的更正。)

每个控制字符(如换行符)的 Unicode 名称都是空字符串。但是,几乎所有字符都由其他标准(如 ASCII 标准)分配了名称,或者已在通用使用中。viacode 返回这些名称作为可用的“最佳”名称。Unicode 6.1 为每个控制字符创建了 Name_Aliases,包括备用名称,如换行符。viacode 使用原始名称“换行符”,而不是备用名称。类似地,返回的 U+FEFF 名称是“零宽度不间断空格”,而不是“字节顺序标记”。

在 Unicode 6.1 之前,4 个控制字符 U+0080、U+0081、U+0084 和 U+0099 没有名称或别名。为了保持向后兼容性,您为这些代码点定义的任何别名都将由此函数返回,优先于官方名称。

一些代码点也有缩写名称,例如“LF”或“NL”。viacode 永远不会返回这些名称。

由于名称更正可能会在未来的 Unicode 版本中添加,因此viacode 返回的名称可能会因此而改变。这是一个罕见的事件,但确实会发生。

自定义翻译器

\N{...} 转义的翻译机制是通用的,并且没有硬编码到 charnames.pm 中。模块可以在以下魔术咒语的范围内安装自定义翻译(在 use 模块的范围内):

sub import {
    shift;
    $^H{charnames} = \&translator;
}

这里 translator() 是一个子例程,它以 CHARNAME 作为参数,并返回要插入字符串中的文本,而不是 \N{CHARNAME} 转义。

这是创建自定义命名代码点序列的唯一方法。

由于要插入的文本在 bytes 模式下和不在 bytes 模式下应该不同,因此该函数应该检查 bytes 标志的当前状态,如:

use bytes ();                      # for $bytes::hint_bits
sub translator {
    if ($^H & $bytes::hint_bits) {
        return bytes_translator(@_);
    }
    else {
        return utf8_translator(@_);
    }
}

有关 CHARNAME 的限制,请参见上面的 "自定义别名"

当然,vianameviacodestring_vianame 也需要被覆盖。

错误

vianame() 通常返回一个序数代码点,但当输入名称为 U+... 格式时,它返回一个 chr。在这种情况下,如果 use bytes 生效并且字符无法放入一个字节中,它将返回 undef 并发出警告。

由于翻译函数的评估(参见 "自定义翻译器")发生在编译(字符串文字)的中间,因此翻译函数不应该执行任何 evalrequire。此限制应该在 Perl 的未来版本中解除(但优先级较低)。