現在のロケールで指定された文字クラスの文字リストを取得するコマンド

現在のロケールで指定された文字クラスの文字リストを取得するコマンド

現在のロケールで、特定の文字クラス ( blank、、alpha...など) のすべての文字のリストを取得する方法は何でしょうか。digit

例えば、

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、2 番目の例では 1 バイト)、同等の Unicode 文字コードポイント、および説明です。

コンテクスト

(編集) 脆弱性はすでに修正され公開されているので、少し背景を説明できます。

私は調査中にその質問をしました脆弱性 2014-0475.には、標準のシステム ロケール検索パスを基準にして解決されるglibcロケールをユーザーが使用できるというバグがありLC_ALL=../../../../tmp/evil-locale、そのため任意のファイルをロケール定義として使用できます。

不正なロケールを作成することができます例えば、1文字あたり1バイトの文字セットではshと他のいくつかの文字を除くほとんどの文字が考慮されました。空白そして、これは典型的な Debian ファイルを解析しながらbash実行されます(そして、たとえば、サーバー ユーザーのログイン シェルとして使用され、サーバーが/変数を受け入れ、攻撃者がサーバーにファイルをアップロードできる場合、ホスティング サーバーでシェル アクセスを取得するために使用される可能性があります)。sh/etc/bash.bashrcgitbashgitsshLC_*LANG

LC_CTYPEさて、で (コンパイルされたロケール定義)を見つけた場合/tmp/evil、それが不正なものであるかどうかをどのようにして、またどのような方法で確認するのでしょうか。

したがって、私の目標は、それらのロケール定義をアンコンパイルすることであり、そうでない場合は、少なくとも特定の文字クラスにどの文字 (およびそのエンコーディング) が含まれているかを知ることです。

それを念頭に置いて:

  • ロケールのソース ファイル ( /usr/share/i18n/localeDebian にあるようなロケール定義) を確認するソリューションは、私のケースでは役に立ちません。
  • Unicode 文字のプロパティは無関係です。私が気にするのは、ロケールの内容だけです。Debian システムでは、不正なロケールは言うまでもなく、2 つの UTF-8 システム ロケール間でも、クラス内の文字のリストが異なる場合があります。
  • バイト/マルチバイトと文字間の変換を行う、やなどのツールは使用できません。これらのツールはrecode、ロケールとは異なる方法で変換を行う可能性がある (実際にそうしている) ためです。pythonperl

答え1

考えられる最終解決策

そこで私は以下の情報をすべて取り入れて、次のような結論に至りました。

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.

また注目すべきはrecodeAPIです:

指定されたプログラムは、recodeその再コーディング ライブラリの単なるアプリケーションです。再コーディング ライブラリは、他の C プログラム用に別途用意されています。再コーディング ライブラリに慣れるには、プログラム自体に慣れるのがよい方法ですrecode

再コーディング ライブラリをインストールしたら、それを使用するには、C プログラムに次の行が必要です。

#include <recode.h>

国際的に使いやすい文字列比較のために、POSIXおよびC標準ではstrcoll()関数:

この関数は、 が指す文字列と が指す文字列strcoll()を比較します。両方の文字列は、現在のロケールの LC_COLLATE カテゴリに適切に解釈されます。s1s2

関数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);
}

文字クラスに関しては、 APIを使用して検索したことをPOSIXすでに述べました。Unicodeの文字とクラスについては、Crecode's 名前付きダンプ希望する出力を得るために文字セットを指定します。もう一度マニュアル:

たとえば、このコマンドrecode l2..full < inputは、ラテン語2UCS-2、として名前付きダンプからのみ接続されますUCS-2。このような場合、recode元の ラテン語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を使用してフランス語の説明が提供されます。ただし、 LANGUAGEまたはLANG環境変数が文字で始まる場合は、フランス語両方の説明が利用可能な場合は、リストの表示はフランス語が優先されます。

上記と同様の構文を、含まれるテストデータセット独自のキャラクターマップを取得するには、次の操作を実行します。

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チャームマップの有無にかかわらず、アスキー文字セットとそれ以上は何もありませんでした。だから、私が得たのはそれだけです。luitしかし、フィルタリングせずに実行すると、odロールバックして同じマップを再度印刷します。\0400.

ただし、上記の方法には 2 つの大きな問題があります。まず、システムの照合順序があります。非 ASCII ロケールの場合、文字セットのバイト値は単純には影響しませんseq。これが、おそらく解決しようとしている問題の核心であると考えられます。

そうですね、GNU のtr's manページには、クラスを順番に拡張すると書かれています[:upper:] [:lower:]が、それほど多くはありません。

何らかの強力なソリューションを実装できると思いますsortが、それはバックエンド プログラミング API にとってはかなり扱いにくいツールになるでしょう。

recodeこの作業は正しく行われますが、先日はプログラムをあまり気に入っていないようでした。今日の編集で、より親しみやすいものになるかもしれませんし、そうでないかもしれません。

GNUは関数ライブラリも提供しておりgettextこの問題に対処する少なくともLC_MESSAGES文脈上は:

- 関数:char * bind_textdomain_codesetconst char *domainname, const char *codeset

このbind_textdomain_codeset関数は、ドメインのメッセージカタログの出力文字セットを指定するために使用できます。 ドメイン名コードセット引数は有効でなければならないコードセット使用できる名前アイコンv_open関数、または null ポインター。

もし、コードセットパラメータはヌルポインタで、bind_textdomain_codeset 現在選択されているコードセットドメイン名 ドメイン名ない場合はNULLを返しますコードセットまだ選択されていません。

このbind_textdomain_codeset関数は複数回使用できます。同じドメイン名引数で複数回使用した場合、後の呼び出しによって前の呼び出しで行われた設定が上書きされます。

このbind_textdomain_codeset関数は、選択されたコードセットの名前を含む文字列へのポインタを返します。この文字列は関数内で内部的に割り当てられ、ユーザーが変更することはできません。 の実行中にシステムがコアから外れた場合 bind_textdomain_codeset、戻り値は NULL になり、グローバル変数 errno がそれに応じて設定されます。

ネイティブを使うこともできますユニコード文字カテゴリー、これは言語に依存せず、POSIX クラスを完全に放棄するか、あるいは前者を呼び出して後者を定義するのに十分な情報を提供するかのいずれかです。

複雑さに加えて、Unicodeは新たな可能性ももたらします。その1つは、各Unicode文字が特定のカテゴリー。「文字」カテゴリに属する​​ 1 つの文字は で一致させることができます 。\p{L}そのカテゴリに属さない 1 つの文字は で一致させることができます\P{L}

繰り返しますが、「文字」は実際には「Unicode コード ポイント」を意味します。 は、\p{L}カテゴリ「文字」の単一のコード ポイントと一致します。入力文字列がà としてエンコードされている場合はU+0061 U+0300aアクセントなしで一致します。入力がàとしてエンコードされている場合はU+00E0、アクセント付きで一致しますà。その理由は、コード ポイントU+0061 (a)と の両方がU+00E0 (à)カテゴリ「文字」に属し、 がU+0300カテゴリ「マーク」に属しているためです。

\P{M}\p{M}*+これで、が と同等である理由がおわかりいただけたと思います\X\P{M}は結合マークではないコード ポイントに一致しますが、\p{M}*+ は結合マークである 0 個以上のコード ポイントに一致します。発音区別符号を含む文字に一致させるには、 を使用します\p{L}\p{M}*+。この最後の正規表現は、エンコード方法に関係なく、常に に一致します 。à絶対的な結合マークがない結合マークなしの非マークにバックトラックが一致しないように\P{M}\p{M}*+、絶対的な結合マークなしの非マークに ...\X

上記の情報を提供した同じウェブサイトでは、Tcl自身のPOSIX-準拠正規表現の実装は、目標を達成するためのもう 1 つの方法となる可能性があります。

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"たとえば、彼ら全員がある程度共有していると思われるもう 1 つの大きな要素は です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-8 をサポートしていない XTerms の仲介役として働くと思われる、ターミナル UTF-8変換デバイスもあります。変換されたすべてのバイトをファイルに記録したり、単純なフィルターとして使用ptyしたりするなど、多くのスイッチを処理します。-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をコンパイルできます。出力は奇妙で、特に役立つわけではありません ( とはまったく異なります) が、上で指定したとおりに生の形式を取得できます。localesI18Ncharmaps

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動作させられないことは重々承知の上で、物欲しそうにスクロールして見たものもいくつかあります。

答え2

少なくとも 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ビット)バイト(ここではIDEOGRAPHIC SPACEの21 21)で表現される状態に切り替わります。一方、EUCJPでは、同じバイトですが、状態切り替え8 番目のビット ( A1 = 21 | 0x80) を反転することで、よりステートレスになります。

つまり、これらの状態のあるエンコーディングでは、特定の文字を書き込む方法が複数あるということです(たとえば、状態切り替えシーケンスは複数あり、上記のコードで示されているシーケンスはそのうちの 1 つ (初期のデフォルト状態からの標準的なシーケンス) にすぎません。

通常のロケールでは、文字は0..0xD7FF、0xE000..0x10FFFFの範囲外には設定できませんが、悪党ロケールでは、wchar_t でサポートされている範囲の任意の文字を使用できます。たとえば、U+DCBA または U+12345678 文字 (または許可されている場合は文字) が使用できるロケールを作成できます。空白そのため、-D SUPPORT_ROGUE_LOCALESこれらをカバーするには でコードをコンパイルする必要がありますが、そうするとリスト全体をスキャンするのにさらに多くの時間がかかります。

recode@mikeserv のソリューションは、独自の変換を使用し、メンテナンスされておらず、0xFFFF までの Unicode 文字しかサポートしておらず、GNU は少なくともマルチバイト文字では動作しないため、使用できませんでしたtr

使えなかった@ChrisDown のaspythonには POSIX 文字クラスへのインターフェースがありません。

Perl を試してみましたが、UTF-8 以外のマルチバイト ロケールの 128 から 255 までのコード ポイントでは正しく動作せず、システムの変換ライブラリも使用されません。

関連情報