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"
使用 pragma use charnames
可存取 Unicode 字元和命名字元序列的名稱,並允許您定義自己的字元和字元序列名稱。
所有形式的 pragma 都能使用以下 3 個函式
"charnames::string_vianame(name)" 用於在執行階段查詢字元名稱或命名字元序列,傳回其字串表示
"charnames::vianame(name)" 用於在執行階段查詢字元名稱(但不是命名字元序列)以取得其序數值(碼點)
"charnames::viacode(code)" 用於執行時期查詢代碼點以取得其 Unicode 名稱。
從 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}"
。另外請注意,\N{...}
可能表示正規表示式量詞,而不是字元名稱,當 ... 是數字(或逗號分隔的數字對(請參閱 "perlreref 中的「QUANTIFIERS」),而且與此實用指令無關。
charnames
實用指令支援引數 :full
、:loose
、:short
、腳本名稱和 自訂別名。
如果存在 :full
,則對於 \N{CHARNAME}
的展開,字串 CHARNAME 會先在標準 Unicode 字元名稱清單中查詢。
:loose
是 :full
的變體,它允許 CHARNAME 的指定較不精確。詳細資訊請參閱 "LOOSE MATCHES"。
如果存在 :short
,而且 CHARNAME 的形式為 SCRIPT:CNAME
,則會在腳本 SCRIPT 中將 CNAME 查詢為字母,如下一段所述。或者,如果 use charnames
與腳本名稱引數一起使用,則對於 \N{CHARNAME}
,名稱 CHARNAME 會在指定的腳本中(按照指定的順序)查詢為字母。自訂別名可以覆寫這些,並在 "CUSTOM ALIASES" 中說明。
對於在給定的腳本 SCRIPTNAME 中查詢 CHARNAME,此實用指令會在標準 Unicode 名稱表格中查詢名稱
SCRIPTNAME CAPITAL LETTER CHARNAME
SCRIPTNAME SMALL LETTER CHARNAME
SCRIPTNAME LETTER CHARNAME
如果 CHARNAME 全部是小寫,則會忽略 CAPITAL
變體,否則會忽略 SMALL
變體,而且 CHARNAME 和 SCRIPTNAME 都會轉換為全部大寫以進行查詢。除此之外,如果也指定了 :loose
,則兩者都會遵循 寬鬆 規則;否則遵循嚴格規則。
請注意,\N{...}
是編譯時期;它是雙引號字串中使用的特殊形式的字串常數;這表示您無法在 \N{...}
內使用變數。如果您想要類似的執行時期功能,請使用 charnames::string_vianame()。
請注意,從 Perl 5.18 開始,名稱 BELL
參照 Unicode 字元 U+1F514,而不是傳統的 U+0007。對於後者,請使用 ALERT
或 BEL
。
在 NAME
未知的狀況下使用 \N{NAME}
是語法錯誤。
對於 \N{NAME}
,如果啟用 use bytes
且輸入名稱為無法放入位元組(即序數大於 255)的字元,則會發生致命錯誤。
否則,任何包含 \N{字元名稱}
或 \N{U+碼點}
的字串都會自動套用 Unicode 規則(請參閱 perlunicode 中的「位元組和字元語意」)。
透過指定 :loose
,會選取 Unicode 的 寬鬆字元名稱比對 規則,而非一般使用的嚴格精確比對。這表示 字元名稱 不必指定得如此精確。大小寫無關緊要(如上所述,腳本除外),底線也不重要,唯一重要的連字號是名稱中字首或字尾的連字號(有一個例外:U+1180 韓文字母中聲 O-E
中的連字號很重要)。此外,不與連字號相鄰的空白也不重要。官方 Unicode 名稱在使用連字號與空白分隔字元組時變化很大,而這個選項讓您不必過於在意。非中介連字號之所以重要的原因,是因為 U+0F60 藏文字母 -A
與 U+0F68 藏文字母 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.dev.org.tw/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 平台上可以是「不換行空白」。
別名可以透過使用匿名雜湊新增
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"
規則。
此外,這兩種方法目前只允許命名單個字元。若要命名一系列字元,請使用 自訂翻譯器(如下所述)。
這是 \N{...}
的執行時間等效項。name 可以是任何表達式,其評估為 \N{...}
下 :full
選項接受的名稱,以 charnames
。此外,作用域中控制 "use charnames"
的任何其他選項都適用,例如 :loose
或任何 腳本清單、:short
選項,或你可能已定義的 自訂別名。
唯一的差異是,由於 string_vianame
是執行時間,而 \N{}
是編譯時間。你無法在 \N{}
內插值(因此 \N{$variable}
不起作用);而且如果輸入名稱未知,string_vianame
會傳回 undef
,而不是語法錯誤。
這類似於 string_vianame
。主要區別在於,在大多數情況下,vianame
會傳回序數碼點,而 string_vianame
會傳回字串。例如,
printf "U+%04X", charnames::vianame("FOUR TEARDROP-SPOKED ASTERISK");
會印出「U+2722」。
這導致其他兩個差異。由於會傳回單一碼點,因此函式無法處理命名字元序列,因為這些序列由多個字元組成(它會為這些傳回 undef
。而且,碼點可以是任何字元的碼點,即使是 use bytes
pragma 下不合法字元的碼點,
請參閱 "BUGS",了解行為與上述描述不同的情況。
傳回數字碼點所指示的字元的完整名稱。例如,
print charnames::viacode(0x2722);
會印出「FOUR TEARDROP-SPOKED ASTERISK」。
傳回的名稱是碼點的「最佳」(定義如下)官方名稱或別名(如果可用);否則,是為其定義的自訂別名(如果已定義);否則,是 undef
。這表示你的別名只會傳回沒有官方 Unicode 名稱(或別名)的碼點,例如私人使用碼點。
如果你為碼點定義多於一個名稱,則無法確定會傳回哪一個名稱。
如前所述,如果代碼點沒有已知的名稱,函數會傳回 undef
。在 Unicode 中,這些名稱的正確名稱是空字串,而 undef
會字串化為空字串。(如果你要求超出 U+10FFFF 的合法 Unicode 最大值,而且你沒有指定別名,你會得到 undef
和一個警告。)
輸入數字必須是非負整數,或以 "U+"
或 "0x"
開頭的字串,其餘部分視為十六進位整數。文字數字常數必須是未簽署的;如果它有前導零或包含非十進位的十六進位數字,它將被解釋為十六進位;否則,它將被解釋為十進位。如果它以 "U+"
開頭,它將被解釋為 Unicode 代碼點;否則,它將被解釋為本機代碼點。(只有小於 256 的代碼點才能在 Unicode 和本機代碼點之間有所不同。)因此,U+41
永遠是拉丁字母「A」;但 0x41
可以在 EBCDIC 平台上是「不換行空白」。
如上文在 "別名" 下所述,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_Alias,包括備用名稱,例如換行符。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
旗標的目前狀態,如下所示
use bytes (); # for $bytes::hint_bits
sub translator {
if ($^H & $bytes::hint_bits) {
return bytes_translator(@_);
}
else {
return utf8_translator(@_);
}
}
請參閱上方的 "自訂別名" 以了解 CHARNAME 的限制。
當然,也需要覆寫 vianame
、viacode
和 string_vianame
。
vianame() 通常會傳回序數代碼點,但當輸入名稱為 U+...
格式時,它會傳回 chr。在此情況下,如果 use bytes
生效,且字元無法放入位元組中,它會傳回 undef
並發出警告。
由於轉譯函數的評估(請參閱 "自訂轉譯器")發生在編譯(字串文字)的過程中,因此轉譯函數不應執行任何 eval
或 require
。此限制應在未來的 Perl 版本中解除(但優先順序較低)。