Locale

在目前語言環境中檢索給定字元類中的字元列表的命令

  • October 30, 2016

有什麼方法可以在目前語言環境中檢索給定字元類(如,…)中的所有字元blank列表alphadigit

例如,

LC_ALL=en_GB.UTF-8 that-command blank

理想情況下,在我的 Debian 系統上,會顯示如下內容:

     09 U+0009 HORIZONTAL TAB
     20 U+0020 SPACE
e1 9a 80 U+1680 OGHAM SPACE MARK
e1 a0 8e U+180E MONGOLIAN VOWEL SEPARATOR
e2 80 80 U+2000 EN QUAD
e2 80 81 U+2001 EM QUAD
e2 80 82 U+2002 EN SPACE
e2 80 83 U+2003 EM SPACE
e2 80 84 U+2004 THREE-PER-EM SPACE
e2 80 85 U+2005 FOUR-PER-EM SPACE
e2 80 86 U+2006 SIX-PER-EM SPACE
e2 80 88 U+2008 PUNCTUATION SPACE
e2 80 89 U+2009 THIN SPACE
e2 80 8a U+200A HAIR SPACE
e2 81 9f U+205F MEDIUM MATHEMATICAL SPACE
e3 80 80 U+3000 IDEOGRAPHIC SPACE

在 C 語言環境中可能會顯示如下內容:

09 U+0009 HORIZONTAL TAB
20 U+0020 SPACE

也就是說,字元在語言環境中以字節數組表示(如第一個範例中的 UTF-8,第二個範例中的單字節)、等效的 Unicode 字元程式碼點和描述。

語境

(編輯)既然漏洞早已被修補和披露,我可以添加一些上下文。

我在調查CVE 2014-0475時問了這個問題。glibc有一個錯誤,它允許使用者使用LC_ALL=../../../../tmp/evil-locale相對於標準系統區域設置搜尋路徑解析的區域設置,因此允許使用任何文件作為區域設置定義。

我可以創建一個流氓語言環境,例如每個字元字元集一個字節,其中大多數字元除了sh還有一些其他字元被認為是空白,這將在解析典型的 Debian文件時bash執行(並且可以用來在例如,提供的託管伺服器用作伺服器使用者的登錄 shell,伺服器接受/變數,攻擊者可以將文件上傳到伺服器)。sh``/etc/bash.bashrc``git``bash``git``ssh``LC_*``LANG

現在,如果我在 中找到LC_CTYPE(編譯的語言環境定義)/tmp/evil,我將如何發現它是一個流氓,以及以何種方式。

所以我的目標是取消編譯那些語言環境定義,如果沒有,至少知道哪個字元(連同它們的編碼)在給定的字元類中。

所以考慮到這一點:

  • 在我的情況下,查看語言環境源文件的解決方案(如 Debian 中的語言環境定義/usr/share/i18n/locale)是沒有用的。
  • Unicode 字元屬性無關緊要。我只關心語言環境的內容。在 Debian 系統上,即使在兩個 UTF-8 系統語言環境之間,更不用說流氓語言環境,一個類中的字元列表也可能不同。
  • 不能使用像recode,pythonperl進行字節/多字節到/從字元轉換的工具,因為它們可能(實際上確實如此)以與語言環境不同的方式進行轉換。

至少在 GNU、FreeBSD 或 Solaris 系統上,這種蠻力方法有效:

#include <wctype.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
 unsigned long i;
 int need_init;
 wctype_t type;
 FILE* to_perl;

 setlocale(LC_ALL,"");
 if (argc != 2) {
   fprintf(stderr, "Usage: %s <type>\n", (argc?argv[0] : "???"));
   exit(1);
 }
 if (!(type = wctype(argv[1]))) {
   fprintf(stderr, "Invalid type: \"%s\"\n", argv[1]);
   exit(1);
 }

 need_init = wctomb(0, 0);

 to_perl = popen("perl -Mcharnames=full -ane '"
                 "printf \"%17s U+%04X %s\n\", join(\" \", @F[1..$#F]),"
                 "$F[0], charnames::viacode($F[0])'", "w");

#ifdef SUPPORT_ROGUE_LOCALES
 for(i=0; i<=0x7fffffff; i++) {
#else
 for(i=0; i<=0x10ffff; i++) {
   if (i == 0xd800) i = 0xe000; /* skip UTF-16 surrogates */
#endif
   if (iswctype(i, type)) {
     int n;
     unsigned char buf[1024];

     if (need_init) wctomb(0, 0);
     n = wctomb(buf, i);

     if (n > 0) {
       int c;
       fprintf(to_perl, "%lu", i);
       for (c = 0; c < n; c++)
         fprintf(to_perl, " %02X", buf[c]);
       putc('\n', to_perl);
     }
   }
 }
 pclose(to_perl);
 return 0;
}

雖然根據 C/POSIX,wchar_t它是一種與 Unicode 無關的不透明類型,並且只保證覆蓋系統語言環境支持的所有字元,但實際上,在大多數支持 Unicode 的系統中,這些值確實對應於 Unicode 程式碼點並且語言環境定義本身基於 Unicode。

Unicode 是所有已知字元集的超集,因此循環遍歷 Unicode 中的所有有效程式碼點(0 到 0xD7FF 和 0xE000 到 0x10FFFF)應該至少列出給定字元集支持的所有字元。

在這裡,我們使用系統的語言環境標準 API 來檢查哪些是給定的類型,並將其轉換為語言環境編碼中的編碼形式。我們使用perl和它的charnames模組只是為了從給定的 Unicode 程式碼點獲取名稱。

在使用有狀態編碼(如 ISO-2022-JP)的語言環境中,我們確保從預設初始狀態顯示編碼形式。

我還沒有找到一個安裝了帶有狀態字元編碼的語言環境的系統,但至少在 GNU 系統上,可以生成一些這樣的流氓語言環境(並且至少 GNU 工具在那些環境中無法正常工作)語言環境)。例如,對於使用 ISO-2022-JP 和普通ja_JP語言環境的自定義語言環境,我得到:

$ LOCPATH=$PWD LC_ALL=ja_JP.ISO-2022-JP ~/list-type blank
      09 U+0009 CHARACTER TABULATION
      20 U+0020 SPACE
  1B 24 42 21 21 U+3000 IDEOGRAPHIC SPACE

與之比較:

$ LC_ALL=ja_JP.eucjp ~/list-type blank
      09 U+0009 CHARACTER TABULATION
      20 U+0020 SPACE
   A1 A1 U+3000 IDEOGRAPHIC SPACE

在 ISO-2022-JP 中,1B 24 42序列 ( \e$B) 從 ASCII 切換到字元表示為 2(7 位)字節的狀態(此處為 21 21 表示 IDEOGRAPHIC SPACE)。在 EUCJP 中,它是相同的字節,但狀態切換是通過翻轉第 8 位 ( A1 = 21 | 0x80) 來完成的,這使其更加無狀態。

這意味著在那些有狀態的編碼中,有幾種方法可以寫入給定的字元(例如,通過插入幾個狀態切換序列),上面程式碼顯示的序列只是其中之一(最初的規範序列)預設狀態)。

雖然對於普通語言環境,字元不能超出 0..0xD7FF、0xE000..0x10FFFF,但對於流氓語言環境,wchar_t 支持的範圍內的任何字元都可以。例如,我可以創建一個語言環境,其中 U+DCBA 或 U+12345678 個字元(或者如果允許它們是字元)是空白的。這就是為什麼您要編譯該程式碼-D SUPPORT_ROGUE_LOCALES以覆蓋這些程式碼,儘管這意味著掃描整個列表需要更多時間。

我不能使用@mikeserv 的解決方案,因為recode它使用了它自己的轉換,不再維護並且只支持最高 0xFFFF 的 Unicode 字元,並且 GNUtr至少不能處理多字節字元。

我不能使用@ChrisDown,因為python它沒有到 POSIX 字元類的介面。

我嘗試過 Perl,但對於 UTF-8 以外的多字節語言環境,128 到 255 之間的程式碼點是虛假的,並且不使用系統的轉換庫。

可能的最終解決方案

所以我已經收集了以下所有資訊並提出了這個:

for class in $(
   locale -v LC_CTYPE | 
   sed 's/combin.*//;s/;/\n/g;q'
) ; do 
   printf "\n\t%s\n\n" $class
   recode u2/test16 -q </dev/null | 
   tr -dc "[:$class:]" | 
   od -A n -t a -t o1z -w12
done

注意

我使用od上面的最終過濾器作為偏好,因為我知道我不會使用多字節字元,它不會正確處理。 recode u2..dump將生成更像問題中指定的輸出並正確處理寬字元。

輸出

       upper

  A   B   C   D   E   F   G   H   I   J   K   L
101 102 103 104 105 106 107 110 111 112 113 114  >ABCDEFGHIJKL<
  M   N   O   P   Q   R   S   T   U   V   W   X
115 116 117 120 121 122 123 124 125 126 127 130  >MNOPQRSTUVWX<
  Y   Z
131 132                                          >YZ<

       lower

  a   b   c   d   e   f   g   h   i   j   k   l
141 142 143 144 145 146 147 150 151 152 153 154  >abcdefghijkl<
  m   n   o   p   q   r   s   t   u   v   w   x
155 156 157 160 161 162 163 164 165 166 167 170  >mnopqrstuvwx<
  y   z
171 172                                          >yz<

       alpha

  A   B   C   D   E   F   G   H   I   J   K   L
101 102 103 104 105 106 107 110 111 112 113 114  >ABCDEFGHIJKL<
  M   N   O   P   Q   R   S   T   U   V   W   X
115 116 117 120 121 122 123 124 125 126 127 130  >MNOPQRSTUVWX<
  Y   Z   a   b   c   d   e   f   g   h   i   j
131 132 141 142 143 144 145 146 147 150 151 152  >YZabcdefghij<
  k   l   m   n   o   p   q   r   s   t   u   v
153 154 155 156 157 160 161 162 163 164 165 166  >klmnopqrstuv<
  w   x   y   z
167 170 171 172                                  >wxyz<

       digit

  0   1   2   3   4   5   6   7   8   9
060 061 062 063 064 065 066 067 070 071          >0123456789<

      xdigit                                                                                          

  0   1   2   3   4   5   6   7   8   9   A   B
060 061 062 063 064 065 066 067 070 071 101 102  >0123456789AB<
  C   D   E   F   a   b   c   d   e   f
103 104 105 106 141 142 143 144 145 146          >CDEFabcdef<

       space

 ht  nl  vt  ff  cr  sp
011 012 013 014 015 040                          >..... <

       print

 sp   !   "   #   $   %   &   '   (   )   *   +
040 041 042 043 044 045 046 047 050 051 052 053  > !"#$%&'()*+<
  ,   -   .   /   0   1   2   3   4   5   6   7
054 055 056 057 060 061 062 063 064 065 066 067  >,-./01234567<
  8   9   :   ;   <   =   >   ?   @   A   B   C
070 071 072 073 074 075 076 077 100 101 102 103  >89:;<=>?@ABC<
  D   E   F   G   H   I   J   K   L   M   N   O
104 105 106 107 110 111 112 113 114 115 116 117  >DEFGHIJKLMNO<
  P   Q   R   S   T   U   V   W   X   Y   Z   [
120 121 122 123 124 125 126 127 130 131 132 133  >PQRSTUVWXYZ[<
  \   ]   ^   _   `   a   b   c   d   e   f   g
134 135 136 137 140 141 142 143 144 145 146 147  >\]^_`abcdefg<
  h   i   j   k   l   m   n   o   p   q   r   s
150 151 152 153 154 155 156 157 160 161 162 163  >hijklmnopqrs<
  t   u   v   w   x   y   z   {   |   }   ~
164 165 166 167 170 171 172 173 174 175 176      >tuvwxyz{|}~<

       graph

  !   "   #   $   %   &   '   (   )   *   +   ,
041 042 043 044 045 046 047 050 051 052 053 054  >!"#$%&'()*+,<
  -   .   /   0   1   2   3   4   5   6   7   8
055 056 057 060 061 062 063 064 065 066 067 070  >-./012345678<
  9   :   ;   <   =   >   ?   @   A   B   C   D
071 072 073 074 075 076 077 100 101 102 103 104  >9:;<=>?@ABCD<
  E   F   G   H   I   J   K   L   M   N   O   P
105 106 107 110 111 112 113 114 115 116 117 120  >EFGHIJKLMNOP<
  Q   R   S   T   U   V   W   X   Y   Z   [   \
121 122 123 124 125 126 127 130 131 132 133 134  >QRSTUVWXYZ[\<
  ]   ^   _   `   a   b   c   d   e   f   g   h
135 136 137 140 141 142 143 144 145 146 147 150  >]^_`abcdefgh<
  i   j   k   l   m   n   o   p   q   r   s   t
151 152 153 154 155 156 157 160 161 162 163 164  >ijklmnopqrst<
  u   v   w   x   y   z   {   |   }   ~
165 166 167 170 171 172 173 174 175 176          >uvwxyz{|}~<

       blank

 ht  sp
011 040                                          >. <

       cntrl

nul soh stx etx eot enq ack bel  bs  ht  nl  vt
000 001 002 003 004 005 006 007 010 011 012 013  >............<
 ff  cr  so  si dle dc1 dc2 dc3 dc4 nak syn etb
014 015 016 017 020 021 022 023 024 025 026 027  >............<
can  em sub esc  fs  gs  rs  us del
030 031 032 033 034 035 036 037 177              >.........<

       punct

  !   "   #   $   %   &   '   (   )   *   +   ,
041 042 043 044 045 046 047 050 051 052 053 054  >!"#$%&'()*+,<
  -   .   /   :   ;   <   =   >   ?   @   [   \
055 056 057 072 073 074 075 076 077 100 133 134  >-./:;<=>?@[\<
  ]   ^   _   `   {   |   }   ~
135 136 137 140 173 174 175 176                  >]^_`{|}~<

       alnum

  0   1   2   3   4   5   6   7   8   9   A   B
060 061 062 063 064 065 066 067 070 071 101 102  >0123456789AB<
  C   D   E   F   G   H   I   J   K   L   M   N
103 104 105 106 107 110 111 112 113 114 115 116  >CDEFGHIJKLMN<
  O   P   Q   R   S   T   U   V   W   X   Y   Z
117 120 121 122 123 124 125 126 127 130 131 132  >OPQRSTUVWXYZ<
  a   b   c   d   e   f   g   h   i   j   k   l
141 142 143 144 145 146 147 150 151 152 153 154  >abcdefghijkl<
  m   n   o   p   q   r   s   t   u   v   w   x
155 156 157 160 161 162 163 164 165 166 167 170  >mnopqrstuvwx<
  y   z

程序員的 API

正如我在下面展示的那樣,recode將為您提供完整的字元圖。根據其手冊,它首先根據DEFAULT_CHARSET環境變數的目前值執行此操作,否則,它完全按照您指定的方式執行:

字元集名稱被省略或留空時,將DEFAULT_CHARSET使用環境中變數的值。如果未定義此變數,則recode庫使用***目前語言環境的編碼。*POSIX兼容的系統上,這取決於環境變數中的第一個非空值,LC_ALL, LC_CTYPE, LANG可以通過命令確定locale charmap.

另外值得注意recode的是它是一個 api

命名的程序recode只是其重新編碼庫的一個應用程序。重新編碼庫可單獨用於其他 C 程序。熟悉重新編碼庫的一個好方法是熟悉recode程序本身。

要在安裝後使用重新編碼庫,C 程序需要有一行:

#include <recode.h>

對於國際友好的字元串比較POSIXC標准定義的strcoll()功能:

strcoll()函式應將 指向的字元串與 指向的字元串進行比較s1s2兩者都被解釋為適合目前語言環境的 LC_COLLATE 類別。

如果成功,該strcoll()函式不應更改 errno 的設置。

由於沒有保留返回值來指示錯誤,因此希望檢查錯誤情況的應用程序應將 errno 設置為 0,然後呼叫 strcoll(),然後檢查 errno。

這是一個單獨的使用範例:

#include <stdio.h>
#include <string.h>

int main ()
{
  char str1[15];
  char str2[15];
  int ret;


  strcpy(str1, "abc");
  strcpy(str2, "ABC");

  ret = strcoll(str1, str2);

  if(ret > 0)
  {
     printf("str1 is less than str2");
  }
  else if(ret < 0) 
  {
     printf("str2 is less than str1");
  }
  else 
  {
     printf("str1 is equal to str2");
  }

  return(0);
}

關於POSIX字元類,您已經註意到您使用CAPI 來查找它們。對於 unicode 字元和類,您可以使用recode's dump-with-names字元集來獲得所需的輸出。再次從其手冊中

例如,該命令recode l2..full < input意味著從Latin-2UCS-2 的必要轉換,因為dump-with-names僅從UCS-2 連接出來。在這種情況下,recode不會顯示轉儲中的原始 Latin-2程式碼,僅顯示相應的UCS-2值。舉一個更簡單的例子,命令

echo 'Hello, world!' | recode us..dump

產生以下輸出:

UCS2   Mne   Description

0048   H     latin capital letter h 
0065   e     latin small letter e
006C   l     latin small letter l 
006C   l     latin small letter l
006F   o     latin small letter o 
002C   ,     comma 
0020  SP     space 
0077   w     latin small letter w 
006F   o     latin small letter o 
0072   r     latin small letter r 
006C   l     latin small letter l 
0064   d     latin small letter d 
0021   !     exclamation mark 
000A   LF    line feed (lf)

描述性註釋以英語和 ASCII 給出,但如果英語描述不可用但法語描述可用,則使用 Latin-1 代替法語描述。但是,如果 LANGUAGEorLANG環境變數以字母fr開頭,那麼當兩個描述都可用時,列表首選項會轉到法語。

使用與上述類似的語法並結合其包含的測試數據集,我可以獲得自己的字元映射:

recode -q u8/test8..dump </dev/null

輸出

UCS2   Mne   Description

0001   SH    start of heading (soh)
0002   SX    start of text (stx)
0003   EX    end of text (etx)    
...
002B   +     plus sign
002C   ,     comma
002D   -     hyphen-minus
...
0043   C     latin capital letter c
0044   D     latin capital letter d
0045   E     latin capital letter e
...
006B   k     latin small letter k
006C   l     latin small letter l
006D   m     latin small letter m
...
007B   (!    left curly bracket
007C   !!    vertical line
007D   !)    right curly bracket
007E   '?    tilde
007F   DT    delete (del)

但對於常見的字元,recode顯然是沒有必要的。這應該為您提供 128 字節字元集中所有內容的命名字元:

printf %b "$(printf \\%04o $(seq 128))" | 
luit -c |
od -A n -t o1z -t a -w12

輸出

001 002 003 004 005 006 007 010 011 012 013 014  >............<
soh stx etx eot enq ack bel  bs  ht  nl  vt  ff
...
171 172 173 174 175 176 177                      >yz{|}~.<
  y   z   {   |   }   ~ del

當然,只表示 128 字節,但那是因為我的語言環境,無論是否utf-8字元映射,都使用ASCII字元集,僅此而已。所以這就是我所得到的。如果我在不luit過濾的情況下執行它,od會將它回滾並再次列印相同的地圖\0400.

但是,上述方法存在兩個主要問題。首先是系統的整理順序——對於非 ASCII 語言環境,字元集的位值不僅僅是seq影響,我認為這很可能是您要解決的問題的核心。

好吧,GNUtr's man頁面聲明它將[:upper:] [:lower:]按順序擴展類 - 但這並不多。

我想可以使用一些笨拙的解決方案來實現,sort但這對於後端程式 API 來說將是一個相當笨拙的工具。

recode會正確地做這件事,但前幾天你似乎不太喜歡這個程序。也許今天的編輯會對它投下更友好的光,也可能不會。

GNU 還提供了gettext函式庫,它似乎能夠至少在上下文中解決這個問題:LC_MESSAGES

— 功能:char * bind_textdomain_codeset( const char *domainname, const char *codeset)

bind_textdomain_codeset函式可用於指定域 domainname的消息目錄的輸出字元集。程式碼集參數必須是可用於iconv_open函式的有效程式碼集名稱,或者是空指針。

如果codeset參數是空指針,則返回名稱為domainname的域 bind_textdomain_codeset 的目前選定程式碼集。如果尚未選擇任何程式碼集,則返回 NULL。

bind_textdomain_codeset功能可以多次使用。如果多次使用同一個域名參數,後面的呼叫會覆蓋前面的設置。

bind_textdomain_codeset函式返回一個指向包含所選程式碼集名稱的字元串的指針。該字元串在函式內部分配,使用者不得更改。如果在執行過程中系統退出核心 bind_textdomain_codeset,則返回值為 NULL,並相應地設置全域變數 errno。

您也可以使用本機Unicode 字元類別,它們與語言無關並且完全放棄 POSIX 類,或者可能呼叫前者為您提供足夠的資訊來定義後者。

除了複雜性之外,Unicode 還帶來了新的可能性。一個是每個 Unicode 字元都屬於某個*類別。*您可以將屬於“字母”類別的單個字元與 \p{L}. 您可以將不屬於該類別的單個字元與\P{L}.

同樣,“字元”實際上意味著“Unicode 程式碼點”。\p{L}匹配“字母”類別中的單個程式碼點。如果您的輸入字元串à 編碼為U+0061 U+0300,則匹配a時不帶重音符號。如果輸入à編碼為U+00E0,則它與à重音匹配。原因是程式碼點U+0061 (a)U+00E0 (à)都在“字母”類別中,而U+0300在“標記”類別中。

您現在應該明白為什麼\P{M}\p{M}*+相當於\X. \P{M}匹配不是組合標記的程式碼點,同時\p{M}*+ 匹配零個或多個組合標記的程式碼點。要匹配包含任何變音符號的字母,請使用\p{L}\p{M}*+. 最後一個正則表達式將始終匹配à,無論它是如何編碼的。所有格量詞確保回溯不會導致\P{M}\p{M}*+匹配沒有跟隨它的組合標記的非標記,這\X 是永遠不會的。

提供上述資訊的同一網站還討論了Tcl自己的符合POSIX正則表達式實現,這可能是實現您目標的另一種方式。

最後一個解決方案我建議您可以查詢LC_COLLATE文件本身以獲得完整且有序的系統字元映射。這似乎並不容易完成,但我在編譯後取得了一些成功,如下localedef所示:

<LC_COLLATE od -j2K -a -w2048 -v  | 
tail -n2 | 
cut -d' ' -f$(seq -s',' 4 2 2048) | 
sed 's/nul\|\\0//g;s/  */ /g;:s;
   s/\([^ ]\{1,3\}\) \1/\1/;ts;
   s/\(\([^ ][^ ]*  *\)\{16\}\)/\1\n/g'

dc1 dc2 dc3 dc4 nak syn etb can c fs c rs c sp ! "
# $ % & ' ( ) * + , - . / 0 1 2
3 4 5 6 7 8 9 : ; < = > ? @ A B
C D E F G H I J K L M N O P Q R
S T U V W X Y Z [ \ ] ^ _ ` a b
c d e f g h i j k l m n o p q r
s t u v w x y z { | } ~ del soh stx etx
eot enq ack bel c ht c vt cr c si dle dc1 del

誠然,它目前存在缺陷,但我希望它至少證明了這種可能性。

一開始臉紅

strings $_/en_GB

#OUTPUT

int_select "<U0030><U0030>"
...
END LC_TELEPHONE

它真的看起來並不多,但後來我開始注意到copy整個列表中的命令。例如,上面的文件似乎copy在*“en_US”*中,另一個似乎它們在某種程度上共享的真正大文件是iso_14651_t1_common.

它相當大:

strings $_ | wc -c

#OUTPUT
431545

這是介紹/usr/share/i18n/locales/POSIX

# Territory:
# Revision: 1.1
# Date: 1997-03-15
# Application: general
# Users: general
# Repertoiremap: POSIX
# Charset: ISO646:1993
# Distribution and use is free, also for
# commercial purposes.
LC_CTYPE
# The following is the POSIX Locale LC_CTYPE.
# "alpha" is by default "upper" and "lower"
# "alnum" is by definiton "alpha" and "digit"
# "print" is by default "alnum", "punct" and the <U0020> character
# "graph" is by default "alnum" and "punct"
upper   <U0041>;<U0042>;<U0043>;<U0044>;<U0045>;<U0046>;<U0047>;<U0048>;\
       <U0049>;<U004A>;<U004B>;<U004C>;<U004D>;<U004E>;<U004F>;

你當然可以grep通過這個,但你可能只是:

recode -lf gb

反而。你會得到這樣的東西:

Dec  Oct Hex   UCS2  Mne  BS_4730

 0  000  00   0000  NU   null (nul)
 1  001  01   0001  SH   start of heading (soh)
...

… 和更多

還有一個luit終端 UTF-8pty翻譯設備,我猜它是不支持 UTF-8 的 XTerms 的中間人。它處理很多開關——例如將所有轉換的字節記錄到文件中或-c作為簡單的|pipe過濾器。

我從來沒有意識到這有這麼多——語言環境和角色地圖等等。這顯然是一件大事,但我想這一切都在幕後進行。至少在我的系統上,有幾百個man 3與語言環境相關的搜尋結果。

而且還有:

zcat /usr/share/i18n/charmaps/UTF-8*gz | less

   CHARMAP
<U0000>     /x00         NULL
<U0001>     /x01         START OF HEADING
<U0002>     /x02         START OF TEXT
<U0003>     /x03         END OF TEXT
<U0004>     /x04         END OF TRANSMISSION
<U0005>     /x05         ENQUIRY
...

這將持續長時間。

這些Xlib函式一直在處理這個問題——luit是那個包的一部分。

這些Tcl_uni...功能也可能被證明是有用的。

只是一點點的<tab>完成和man搜尋,我在這個主題上學到了很多東西。

使用- 您可以在您的目錄localedef中編譯。輸出很時髦,而且不是特別有用 - 一點也不像- 但你可以像我一樣獲得上面指定的原始格式:locales``I18N``charmaps

mkdir -p dir && cd $_ ; localedef -f UTF-8 -i en_GB ./ 

ls -l
total 1508
drwxr-xr-x 1 mikeserv mikeserv      30 May  6 18:35 LC_MESSAGES
-rw-r--r-- 1 mikeserv mikeserv     146 May  6 18:35 LC_ADDRESS
-rw-r--r-- 1 mikeserv mikeserv 1243766 May  6 18:35 LC_COLLATE
-rw-r--r-- 1 mikeserv mikeserv  256420 May  6 18:35 LC_CTYPE
-rw-r--r-- 1 mikeserv mikeserv     376 May  6 18:35 LC_IDENTIFICATION
-rw-r--r-- 1 mikeserv mikeserv      23 May  6 18:35 LC_MEASUREMENT
-rw-r--r-- 1 mikeserv mikeserv     290 May  6 18:35 LC_MONETARY
-rw-r--r-- 1 mikeserv mikeserv      77 May  6 18:35 LC_NAME
-rw-r--r-- 1 mikeserv mikeserv      54 May  6 18:35 LC_NUMERIC
-rw-r--r-- 1 mikeserv mikeserv      34 May  6 18:35 LC_PAPER
-rw-r--r-- 1 mikeserv mikeserv      56 May  6 18:35 LC_TELEPHONE
-rw-r--r-- 1 mikeserv mikeserv    2470 May  6 18:35 LC_TIME

然後od你可以閱讀它 - 字節和字元串:

od -An -a -t u1z -w12 LC_COLLATE | less

etb dle enq  sp dc3 nul nul nul   T nul nul nul
 23  16   5  32  19   0   0   0  84   0   0   0  >... ....T...<
...

儘管距離贏得選美比賽還有很長的路要走,但這是可用的輸出。當然od,它也可以隨心所欲地配置。

我想我也忘記了這些:

   perl -mLocale                                                                                       

-- Perl module --
Locale::Codes                    Locale::Codes::LangFam           Locale::Codes::Script_Retired
Locale::Codes::Constants         Locale::Codes::LangFam_Codes     Locale::Country
Locale::Codes::Country           Locale::Codes::LangFam_Retired   Locale::Currency
Locale::Codes::Country_Codes     Locale::Codes::LangVar           Locale::Language
Locale::Codes::Country_Retired   Locale::Codes::LangVar_Codes     Locale::Maketext
Locale::Codes::Currency          Locale::Codes::LangVar_Retired   Locale::Maketext::Guts
Locale::Codes::Currency_Codes    Locale::Codes::Language          Locale::Maketext::GutsLoader
Locale::Codes::Currency_Retired  Locale::Codes::Language_Codes    Locale::Maketext::Simple
Locale::Codes::LangExt           Locale::Codes::Language_Retired  Locale::Script
Locale::Codes::LangExt_Codes     Locale::Codes::Script            Locale::gettext
Locale::Codes::LangExt_Retired   Locale::Codes::Script_Codes      locale

我可能忘記了它們,因為我無法讓它們工作。我從不使用Perl,也不知道如何正確載入模組。但是man頁面看起來很漂亮。無論如何,有些事情告訴我你會發現呼叫 Perl 模組至少比我簡單一點。而且,這些已經在我的電腦上——我什至從未使用過 Perl。還有一些值得注意的是I18N,我很清楚我不會讓它們工作,因此我若有所思地滾動。

引用自:https://unix.stackexchange.com/questions/128192