Perintah untuk mengambil daftar karakter dalam kelas karakter yang diberikan di lokal saat ini

18

Apa yang bisa menjadi cara untuk mengambil daftar semua karakter dalam kelas karakter tertentu (seperti blank, alpha, digit...) di lokal saat ini.

Contohnya,

LC_ALL=en_GB.UTF-8 that-command blank

idealnya, pada sistem Debian saya, akan menampilkan sesuatu seperti:

      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

Dan di lokal C dapat menampilkan sesuatu seperti:

09 U+0009 HORIZONTAL TAB
20 U+0020 SPACE

Yaitu, representasi karakter di lokal dalam hal array byte, (seperti UTF-8 dalam contoh pertama, dan byte tunggal pada yang kedua), kode karakter Unicode yang setara, dan deskripsi.

Konteks

(sunting) Sekarang kerentanan telah lama ditambal dan diungkapkan, saya dapat menambahkan sedikit konteks.

Saya mengajukan pertanyaan itu pada saat saya sedang menyelidiki CVE 2014-0475 . glibcmemiliki bug yang memungkinkan pengguna menggunakan lokal seperti LC_ALL=../../../../tmp/evil-localeyang diselesaikan relatif terhadap jalur pencarian lokal sistem standar dan dengan demikian memungkinkan untuk menggunakan file apa pun sebagai definisi lokal.

Saya bisa membuat lokal nakal misalnya dengan satu byte per karakter charset di mana sebagian besar karakter kecuali s, hdan beberapa lainnya dianggap kosong dan itu akan bashdijalankan shketika mengurai /etc/bash.bashrcfile Debian yang khas (dan yang dapat digunakan untuk mendapatkan akses shell pada sebuah githosting server misalnya disediakan bashdigunakan sebagai shell login dari gitpengguna server dan bahwa sshserver menerima LC_*/ LANGvariabel dan bahwa penyerang dapat mengunggah file ke server).

Sekarang, jika saya menemukan LC_CTYPE(mengkompilasi definisi lokal) di /tmp/evil, bagaimana saya mengetahui itu adalah sesuatu yang jahat dan dengan cara apa.

Jadi tujuan saya adalah untuk meng-un-compile definisi lokal tersebut, dan jika tidak, setidaknya tahu karakter mana (bersama dengan encoding mereka) yang ada di kelas karakter yang diberikan.

Maka dengan itu dalam pikiran:

  • Solusi yang melihat file sumber untuk lokal (definisi lokal seperti yang ada di /usr/share/i18n/localeDebian) tidak ada gunanya dalam kasus saya.
  • Properti karakter Unicode tidak relevan. Saya hanya peduli dengan apa yang dikatakan penduduk setempat. Pada sistem Debian, bahkan di antara dua lokal sistem UTF-8, apalagi yang nakal, daftar karakter di kelas dapat berbeda.
  • Alat-alat seperti recode, pythonatau perlyang melakukan byte / multi-byte ke / dari konversi karakter tidak dapat digunakan karena mereka dapat (dan dalam praktiknya melakukan) membuat konversi dengan cara yang berbeda dari lokal.
Stéphane Chazelas
sumber
Untuk sebagian besar lokal pada akhirnya berasal dari hal-hal LC_CTYPE di (dengan glibc) /usr/share/i18n/locales/i18n... yang tentu saja sebagian besar berasal dari Database Karakter Unicode. Tentu saja, akan menyenangkan memiliki perintah
derobert
@derobert, ya, sementara locale(setidaknya yang GNU) mengambil banyak informasi yang disimpan dalam banyak kategori, hal-hal yang tidak penting adalah LC_CTYPE dan LC_COLLATE. Saya ingin tahu apakah ada API tersembunyi untuk mengambil informasi itu atau mengompilasi informasi lokal.
Stéphane Chazelas
Ya - Anda bisa mendapatkan info yang diuraikan - Saya akhirnya berhasil menyelesaikan edit saya. Ada beberapa perintah yang mungkin sudah Anda instal - setidaknya saya lakukan, dan saya bahkan tidak tahu tentang mereka. Saya harap ini membantu. Secara khusus recodedan uconvdapat memberi Anda apa yang Anda katakan Anda cari. Mungkin bahkan adil luitdan odkurasa ...
mikeserv
Itu sangat baik! Itu berarti Anda tidak perlu perlsama sekali, saya pikir.
mikeserv
Saya pada dasarnya dapat mengekstrak charset saya LC_CTYPEhanya dengan od -A n -t c <LC_CTYPE | tsortMungkin Anda sudah mencobanya, tetapi saya belum pernah mendengarnya sebelumnya dan saya membacanya infodan mengingatkan saya akan hal ini - dan sepertinya berhasil. Ada juga ptxtapi saya pikir itu kurang relevan. Bagaimanapun, jika Anda belum mencobanya dan memutuskan untuk melakukannya - peringatan yang adil - itu memang membutuhkan sedikit kesabaran. lehman.cuny.edu/cgi-bin/man-cgi?tsort+1
mikeserv

Jawaban:

7

SOLUSI AKHIR YANG MUNGKIN

Jadi saya telah mengambil semua informasi di bawah ini dan menghasilkan ini:

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

CATATAN :

Saya menggunakan odsebagai filter terakhir di atas untuk preferensi dan karena saya tahu saya tidak akan bekerja dengan karakter multi-byte, yang tidak akan ditangani dengan benar. recode u2..dumpkeduanya akan menghasilkan keluaran lebih seperti yang ditentukan dalam pertanyaan dan menangani karakter lebar dengan benar.

KELUARAN

        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 PROGRAMMER

Seperti yang saya tunjukkan di bawah, recodeakan memberi Anda peta karakter lengkap Anda. Menurut manualnya, ia melakukan ini pertama sesuai dengan nilai saat ini dari DEFAULT_CHARSETvariabel lingkungan, atau, jika gagal, ia beroperasi persis seperti yang Anda tentukan:

Ketika nama rangkaian karakter dihilangkan atau dibiarkan kosong, nilai DEFAULT_CHARSETvariabel dalam lingkungan digunakan sebagai gantinya. Jika variabel ini tidak didefinisikan, recodeperpustakaan menggunakan pengkodean lokal saat ini. Pada sistem yang mendukung POSIX , ini tergantung pada nilai non-kosong pertama di antara variabel lingkungan LC_ALL, LC_CTYPE, LANGdan dapat ditentukan melalui perintahlocale charmap.

Juga perlu diperhatikan recodeadalah bahwa ini adalah api :

Program bernama recodehanyalah aplikasi perpustakaan pengodeannya. Perpustakaan pengodean ulang tersedia secara terpisah untuk program C lainnya. Cara yang baik untuk mendapatkan keakraban dengan perpustakaan pengodean ulang adalah untuk berkenalan dengan recodeprogram itu sendiri.

Untuk menggunakan perpustakaan pengodean ulang setelah diinstal, program C perlu memiliki baris:

#include <recode.h>

Untuk perbandingan string yang ramah internasional POSIXdan Cstandar mendefinisikan strcoll()fungsi:

The strcoll()Fungsi akan membandingkan string ditunjukkan oleh s1ke string yang ditunjukkan oleh s2, baik ditafsirkan sesuai dengan kategori LC_COLLATE dari lokal saat ini.

The strcoll()Fungsi tidak akan mengubah pengaturan errno jika berhasil.

Karena tidak ada nilai balik yang dicadangkan untuk menunjukkan kesalahan, aplikasi yang ingin memeriksa situasi kesalahan harus menetapkan errno ke 0, lalu panggil strcoll(), lalu periksa errno.

Berikut ini adalah secara terpisah terletak contoh penggunaannya:

#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);
}

Mengenai POSIXkelas karakter, Anda telah mencatat Anda menggunakan CAPI untuk menemukannya. Untuk karakter dan kelas unicode Anda bisa menggunakan charset recode's dump-with-names untuk mendapatkan hasil yang diinginkan. Dari manualnya lagi :

Misalnya, perintah tersebut recode l2..full < inputmenyiratkan konversi yang diperlukan dari Latin-2 ke UCS-2, karena dump-with-names hanya terhubung dari UCS-2. Dalam kasus tersebut, recodetidak menampilkan kode Latin-2 asli di dump, hanya nilai UCS-2 yang sesuai . Untuk memberikan contoh yang lebih sederhana, perintah

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

menghasilkan output berikut:

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)

Komentar deskriptif diberikan dalam bahasa Inggris dan ASCII, namun jika deskripsi bahasa Inggris tidak tersedia tetapi yang Prancis, maka deskripsi Perancis diberikan sebagai gantinya, menggunakan bahasa Latin-1. Namun, jika variabel LANGUAGEatau LANGlingkungan dimulai dengan huruf fr , maka daftar preferensi akan ke Prancis ketika kedua deskripsi tersedia.

Menggunakan sintaksis yang mirip dengan yang di atas dikombinasikan dengan dataset tes yang disertakan saya bisa mendapatkan peta karakter saya sendiri dengan:

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

KELUARAN

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)

Tetapi untuk karakter umum, recodetampaknya tidak perlu. Ini akan memberi Anda charset bernama untuk semua yang ada di charset 128 byte:

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

KELUARAN

 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

Tentu saja, hanya 128-byte yang diwakili, tetapi itu karena lokal saya, utf-8 charmaps atau tidak, menggunakan charset ASCII dan tidak lebih. Jadi hanya itu yang saya dapat. Jika saya menjalankannya tanpa luitmenyaringnya, odakan menggulungnya kembali dan mencetak peta yang sama lagi\0400.

Ada dua masalah utama dengan metode di atas. Pertama, ada susunan susunan sistem - untuk non-ASCII lokal nilai-nilai gigitan untuk rangkaian tidak hanya seqmempengaruhi, yang, seperti yang saya pikirkan, kemungkinan merupakan inti dari masalah yang Anda coba selesaikan.

Yah, tr's manhalaman GNU menyatakan bahwa itu akan memperluas [:upper:] [:lower:]kelas secara berurutan - tapi itu tidak banyak.

Saya membayangkan beberapa solusi yang berat dapat diimplementasikan dengan sorttetapi itu akan menjadi alat yang agak sulit untuk API pemrograman backend.

recodeakan melakukan hal ini dengan benar, tetapi Anda sepertinya tidak terlalu menyukai program tersebut tempo hari. Mungkin suntingan hari ini akan memberikan cahaya yang lebih bersahabat atau mungkin tidak.

GNU juga menawarkan gettextfungsi perpustakaan, dan tampaknya mampu mengatasi masalah ini setidaknya untuk LC_MESSAGESkonteksnya:

- Fungsi: char * bind_textdomain_codeset( const char *domainname, const char *codeset)

The bind_textdomain_codesetfungsi dapat digunakan untuk menentukan set karakter output untuk pesan katalog untuk domain domainname . The codeset Argumen harus valid codeset nama yang dapat digunakan untuk iconv_open fungsi, atau null pointer.

Jika parameter codeset adalah penunjuk nol, bind_textdomain_codeset mengembalikan set kode yang saat ini dipilih untuk domain dengan nama domainname . Ia mengembalikan NULL jika tidak ada kode yang dipilih.

The bind_textdomain_codesetfungsi dapat digunakan beberapa kali. Jika digunakan beberapa kali dengan argumen domainname yang sama, panggilan selanjutnya menimpa pengaturan yang dibuat oleh yang sebelumnya.

The bind_textdomain_codesetmengembalikan fungsi pointer ke string yang berisi nama codeset yang dipilih. String dialokasikan secara internal dalam fungsi dan tidak boleh diubah oleh pengguna. Jika sistem keluar dari inti selama eksekusi bind_textdomain_codeset, nilai kembali adalah NULL dan errno variabel global diatur sesuai.

Anda juga dapat menggunakan kategori karakter Unicode asli , yang independen terhadap bahasa dan melepaskan kelas POSIX, atau mungkin memanggil yang pertama untuk memberi Anda cukup informasi untuk mendefinisikan yang terakhir.

Selain komplikasi, Unicode juga membawa kemungkinan baru. Salah satunya adalah bahwa setiap karakter Unicode milik kategori tertentu . Anda dapat mencocokkan satu karakter yang termasuk dalam kategori "huruf" dengan \p{L}. Anda dapat mencocokkan satu karakter yang tidak termasuk dalam kategori itu \P{L}.

Sekali lagi, "karakter" benar-benar berarti "titik kode Unicode". \p{L}cocok dengan satu titik kode dalam kategori "huruf". Jika string input Anda à dikodekan sebagai U+0061 U+0300, string tersebut cocok atanpa aksen. Jika input àdikodekan sebagai U+00E0, itu cocok àdengan aksen. Alasannya adalah bahwa kedua kode menunjuk U+0061 (a)dan U+00E0 (à)berada dalam kategori "huruf", sedangkan U+0300berada dalam kategori "tanda".

Anda sekarang harus mengerti mengapa \P{M}\p{M}*+itu setara dengan \X. \P{M}cocok dengan titik kode yang bukan tanda menggabungkan, sedangkan \p{M}*+ cocok dengan nol atau lebih titik kode yang menggabungkan tanda. Untuk mencocokkan surat termasuk diakritik, gunakan \p{L}\p{M}*+. Regex terakhir ini akan selalu cocok à, terlepas dari bagaimana dikodekan. Kuantif posesif memastikan bahwa menelusuri kembali tidak menyebabkan \P{M}\p{M}*+mencocokkan non-mark tanpa menggabungkan tanda yang mengikutinya, yang \X tidak akan pernah berhasil.

Website yang sama yang memberikan informasi atas juga membahas Tclsendiri 's POSIX compliant implementasi regex yang mungkin cara lain untuk mencapai tujuan Anda.

Dan yang terakhir di antara solusi saya akan menyarankan agar Anda dapat menginterogasi LC_COLLATEfile itu sendiri untuk peta karakter sistem lengkap dan teratur . Ini mungkin tampaknya tidak mudah dilakukan, tetapi saya mencapai beberapa keberhasilan dengan yang berikut setelah mengkompilasinya localedefseperti yang ditunjukkan di bawah ini:

<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

Memang, saat ini, cacat, tapi saya harap itu menunjukkan kemungkinan setidaknya.

DI BLUSH PERTAMA

strings $_/en_GB

#OUTPUT

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

Itu benar-benar tidak terlihat banyak tetapi kemudian saya mulai memperhatikan copyperintah di seluruh daftar. File di atas tampaknya copydi "en_US" misalnya, dan satu lagi yang benar-benar besar yang tampaknya mereka semua bagikan pada tingkat tertentu iso_14651_t1_common.

Cukup besar:

strings $_ | wc -c

#OUTPUT
431545

Inilah intro untuk /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>;

...

Anda dapat grepmelalui ini tentu saja, tetapi Anda mungkin hanya:

recode -lf gb

Sebagai gantinya. Anda akan mendapatkan sesuatu seperti ini:

Dec  Oct Hex   UCS2  Mne  BS_4730

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

... DAN LEBIH BANYAK

Ada juga perangkat terjemahan luitterminal UTF-8 yang ptysaya kira berfungsi sebagai perantara untuk XTerms tanpa dukungan UTF-8. Ini menangani banyak switch - seperti mencatat semua byte yang dikonversi ke file atau -csebagai |pipefilter sederhana .

Saya tidak pernah menyadari ada begitu banyak hal ini - peta karakter dan lokal dan semua itu. Ini tampaknya masalah yang sangat besar tapi saya kira itu semua terjadi di belakang layar. Ada - setidaknya di sistem saya - beberapa ratus man 3hasil terkait untuk pencarian terkait lokal.

Dan juga ada:

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
...

Itu akan berlangsung untuk waktu yang sangat lama.

The Xlibfungsi menangani ini semua waktu - luitadalah bagian dari paket itu.

The Tcl_uni...fungsi mungkin terbukti bermanfaat juga.

hanya sedikit <tab>penyelesaian dan manpencarian dan saya sudah belajar banyak tentang hal ini.

Dengan localedef- Anda dapat mengkompilasi localesdalam I18Ndirektori Anda . Outputnya funky, dan tidak terlalu berguna - tidak seperti charmapssama sekali - tetapi Anda bisa mendapatkan format mentah seperti yang Anda tentukan di atas seperti yang saya lakukan:

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

Kemudian dengan odAnda dapat membacanya - byte dan string:

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...<
...

Meskipun masih jauh dari memenangkan kontes kecantikan, itu adalah hasil yang dapat digunakan. Dan oddapat dikonfigurasi seperti yang Anda inginkan juga, tentu saja.

Saya kira saya juga lupa tentang ini:

    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

Saya mungkin lupa tentang mereka karena saya tidak bisa membuatnya bekerja. Saya tidak pernah menggunakan Perldan saya tidak tahu cara memuat modul dengan benar saya kira. Tapi manhalaman - halamannya terlihat cukup bagus. Bagaimanapun, ada sesuatu yang memberitahu saya Anda akan menemukan memanggil modul Perl setidaknya sedikit lebih sulit daripada saya. Dan, sekali lagi, ini sudah ada di komputer saya - dan saya bahkan tidak pernah menggunakan Perl. Ada juga beberapa I18Nyang saya gulir secara salah dengan mengetahui sepenuhnya bahwa saya tidak akan membuat mereka bekerja juga.

mikeserv
sumber
1
Itu semua info yang sangat bagus dan berguna, tetapi memberikan informasi tentang file sumber (dalam i18n) yang mungkin atau mungkin tidak digunakan untuk menghasilkan lokal yang saya gunakan saat ini. Informasi lokal mungkin berasal dari /usr/lib/locale/locale-archiveatau /some/dir/LC_CTYPE, dan itulah bagian yang relevan dengan lokal saya yang disimpan dalam file-file yang saya cari.
Stéphane Chazelas
@StephaneChezales - jadi ekstrak saja LC_STUFFdari arsip Anda dengan localedef- itu juga. Saya bisa demo juga, saya kira. Anda juga dapat melihat itu dan hampir semua yang lainnya dengan stringsatau odyang lainnya. Bagaimanapun, saya melakukannya. Tapi omong-omong - charmaps adalah lokasi yang Anda gunakan saat ini - dan localedefakan melaporkannya juga. Itu juga apa recode.
mikeserv
Anda pada dasarnya mengatakan bahwa kita dapat melakukan dengan tangan apa pustaka sistem untuk melakukan informasi kelas karakter kueri, tapi itu akan membutuhkan ribuan baris kode untuk melakukan itu dengan andal dan hasilnya akan spesifik sistem. (parsing lingkungan dengan cara yang sama perpustakaan sistem tidak (LOCPATH, LANG, LANGUAGE, LC_CTYPE ..., mengidentifikasi di mana mencari data, ekstrak itu ...). Saya tidak bisa melihat cara mengekstrak barang dari arsip dengan localedef sekalipun
Stéphane Chazelas
@StephaneChazelas - saya tidak menyarankan Anda melakukannya dengan tangan - saya sarankan Anda melakukannya dengan komputer - menggunakan sistem biner seperti od, recode, uconv, dan sisanya. Tetapi itu adalah kesalahan saya - bukan localedefitu yang mengekstraknya, tapi itu recodeyang akan. Anda harus memeriksa info recode- dan selain recodeperintah tabel yang saya tunjukkan ada banyak hal yang sama - dan itu akan menangani hal-hal dengan cara yang sama, saya pikir. Itu tidak hanya menarik charset Anda keluar dari udara tipis. Dalam kasus apa pun saya memang memiliki harapan besar untuk perlmodul - modul tersebut - apakah Anda mencobanya?
mikeserv
1
Jika ada API untuk mengambil daftar karakter di kelas karakter tertentu di lokal saat ini, maka itulah yang saya cari. Jika Anda dapat menunjukkan cara melakukan ini, saya akan menerima jawabannya. Satu-satunya hal yang dapat saya pikirkan (dan bagaimana saya mendapatkan "output yang diharapkan" dalam pertanyaan saya) adalah menggunakan iswblank(3)untuk semua nilai karakter yang mungkin.
Stéphane Chazelas
1

Setidaknya pada sistem GNU, FreeBSD atau Solaris, pendekatan brute-force ini bekerja:

#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;
}

Sementara per C / POSIX, wchar_tadalah tipe buram yang tidak memiliki hubungan dengan Unicode dan hanya dijamin untuk mencakup semua karakter yang didukung oleh lokal sistem, dalam praktiknya, di sebagian besar sistem yang mendukung Unicode, nilainya sesuai dengan poin kode Unicode dan definisi lokal sendiri didasarkan pada Unicode.

Unicode dimaksudkan sebagai superset dari semua charset yang dikenal, jadi mengulang semua poin kode yang valid di Unicode (0 hingga 0xD7FF dan 0xE000 hingga 0x10FFFF) harus mencantumkan setidaknya semua karakter yang didukung oleh charset yang diberikan.

Di sini, kami menggunakan API standar lokal sistem untuk memeriksa yang mana dari jenis yang diberikan dan mengonversinya ke bentuk yang disandikan dalam pengkodean lokal. Kami menggunakan perldan charnamesmodulnya hanya untuk mendapatkan nama dari titik kode Unicode yang diberikan.

Pada lokal yang menggunakan penyandian stateful seperti ISO-2022-JP, kami memastikan formulir yang disandikan ditampilkan dari keadaan awal default.

Saya tidak menemukan sistem yang telah menginstal lokal dengan pengkodean karakter stateful tetapi setidaknya pada sistem GNU, dimungkinkan untuk menghasilkan beberapa sehingga lokal jahat dapat dibuat untuk (dan setidaknya alat GNU tidak berfungsi dengan baik pada mereka lokal). Misalnya, dengan lokal kustom yang menggunakan ISO-2022-JP dengan ja_JPlokal normal , saya mendapatkan:

$ 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

Dibandingkan dengan:

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

Dalam ISO-2022-JP, 1B 24 42urutan ( \e$B) beralih dari ASCII ke keadaan di mana karakter dinyatakan sebagai 2 (7-bit) byte (di sini 21 21 untuk ruang IDEOGRAPHIC itu). Sementara di EUCJP, itu adalah byte yang sama tetapi pengalihan status dilakukan dengan membalik bit ke-8 ( A1 = 21 | 0x80) yang membuatnya lebih stateless.

Itu berarti bahwa dalam pengkodean stateful, ada beberapa cara untuk menulis karakter yang diberikan (misalnya dengan memasukkan beberapa urutan switching keadaan ), dan urutan yang ditunjukkan oleh kode di atas hanya salah satunya (yang kanonik dari inisial keadaan default).

Sedangkan untuk lokal normal, karakter tidak boleh di luar 0..0xD7FF, 0xE000..0x10FFFF, untuk lokal jahat , karakter apa pun dalam kisaran yang didukung oleh wchar_t mungkin. Misalnya, saya dapat membuat lokal tempat karakter U + DCBA atau U + 12345678 (atau akan menjadi karakter jika diizinkan) kosong . Itu sebabnya Anda ingin mengkompilasi kode itu dengan -D SUPPORT_ROGUE_LOCALESuntuk menutupi itu, meskipun itu berarti dibutuhkan lebih banyak waktu untuk memindai seluruh daftar.

Saya tidak dapat menggunakan solusi @ mikeserv karena recodemenggunakan konversi sendiri, tidak lagi dipertahankan dan hanya mendukung karakter Unicode hingga 0xFFFF, dan trsetidaknya GNU tidak bekerja dengan karakter multi-byte.

Saya tidak bisa menggunakan @ ChrisDown karena pythontidak memiliki antarmuka ke kelas karakter POSIX.

Saya mencoba Perl, tetapi itu palsu untuk titik kode antara 128 dan 255 untuk multi-byte lokal selain UTF-8 dan tidak menggunakan perpustakaan konversi sistem.

Stéphane Chazelas
sumber
Saya pikir ini secara efektif satu-satunya cara untuk melakukannya, tetapi menderita beberapa masalah, dimulai dengan fakta bahwa Anda menggunakan pengetahuan sebelumnya untuk memutuskan tentang berbagai titik temu hukum. Secara teori setidaknya, jika Anda menggunakan charmap Unicode, kelas karakter tidak tergantung pada skrip (menurut standar Unicode, bukan C locales), tetapi "kategori umum" Unicode juga tidak sama dengan kelas karakter C. BTW, i18n ctypes glibc mencakup dua kelas karakter lagi: combiningdan combining_level3(yaitu iswctype(i, wctype("combining")))
rici
@rici, lihat edit (dan juga pertanyaan).
Stéphane Chazelas