Команда для отримання списку символів у заданому класі символів у поточному мові


18

Що може бути спосіб , щоб отримати список всіх символів в заданому класі символів (як 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 у першому прикладі та однобайтовий у другому), еквівалентна кодова точка символу Unicode та опис.

Контекст

(редагувати) Тепер, коли вразливість уже давно виправлена ​​та розкрита, я можу додати трохи контексту.

Я задавав це запитання під час розслідування CVE 2014-0475 . glibcпомилка в тому, що вона дозволяє користувачеві використовувати подібні локалі LC_ALL=../../../../tmp/evil-locale, які вирішуються відносно стандартного шляху пошуку локальної системи, і таким чином дозволяють використовувати будь-який файл як визначення локалі.

Я міг би створити невідповідний локал, наприклад, з одним байтом на діаграму символів, де більшість символів, за винятком s, hі кілька інших вважалися пробілами, які bashзапускатимуться shпід час аналізу типового /etc/bash.bashrcфайлу Debian (і це можна використовувати для отримання доступу до оболонки на gitНаприклад, наданий хостинг-сервер bashвикористовується як оболонка входу користувача gitсервера, і sshсервер приймає LC_*/ LANGзмінює і зловмисник може завантажувати файли на сервер).

Тепер, якщо я коли-небудь знайшов LC_CTYPE(складене визначення локалі) в /tmp/evil, як би я дізнався, що це був шахрай і в який спосіб.

Тож моя мета - скасувати компіляцію цих локальних визначень, а якщо ні, то принаймні знати, який символ (разом з їх кодуванням) є в заданому класі символів.

Отже, маючи це на увазі:

  • Рішення, які дивляться на вихідні файли для локалі (визначення локалі, як те, що в /usr/share/i18n/localeDebian), в моєму випадку не мають користі.
  • Властивості символів Unicode не мають значення. Мене цікавить лише те, що говорить локал. У системі Debian, навіть між двома локальними системами UTF-8, не кажучи вже про шахрайських, список символів у класі може бути різним.
  • Такі інструменти , як recode, pythonабо perlщо робити байт / мульти-байт / с перетворення символів не може бути використаний , як вони можуть (і на практиці роблять) зробити перетворення інакше , ніж локалі.

Для більшості локальних версій вона в кінцевому підсумку походить з матеріалів LC_CTYPE в (з glibc) /usr/share/i18n/locales/i18n... що, звичайно, походить з бази даних символів Unicode. Звичайно, було б непогано мати команду
derobert

@derobert, так, хоча locale(принаймні GNU) отримує багато інформації, що зберігається в багатьох категоріях, речі, які вона не є, є найважливішими в LC_CTYPE та LC_COLLATE. Цікаво, чи є прихований API, щоб отримати цю інформацію або скасувати інформацію про локальну мову.
Стефан Шазелас

Так - ви можете розібрати цю інформацію - я нарешті прийшов до завершення редагування. Є кілька команд, які ви, мабуть, вже встановили - принаймні я це зробив, і про них я навіть не знав. Я сподіваюся, що це допомагає. Конкретно recodeі uconvможе дати вам те, що ви сказали, що шукаєте. Можливо, навіть просто luitі odя здогадуюсь ...
mikeserv

Це дуже добре! Це означає, що тобі perlвзагалі не потрібно , я думаю.
mikeserv

Мені здається, я зможу в основному витягнути свою гарнітуру LC_CTYPEз просто od -A n -t c <LC_CTYPE | tsortНапевно, ви вже пробували її, але я ніколи не чув про неї раніше, і я читав, infoі це нагадало мені про це - і, здається, працює. Є також, ptxале я думаю, що це менш актуально. У будь-якому випадку, якщо ви цього не пробували і вирішили зробити це - справедливе попередження - це вимагає трохи терпіння. lehman.cuny.edu/cgi-bin/man-cgi?tsort+1
mikeserv

Відповіді:


7

МОЖЛИВО ЗАВІДКОВЕ РІШЕННЯ

Отож, я взяв усю нижченаведену інформацію і прийшов до цього:

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>

Для порівняння рядків з міжнародними стандартами Функція POSIXта Cстандарти визначають strcoll():

strcoll()Функція повинна порівнювати рядок , на яку вказує s1на рядок , на яку вказує s2, як інтерпретуються в залежності від обставин до LC_COLLATE категорії поточної локалі.

strcoll()Функція не змінює настройки егто в разі успіху.

Оскільки значення вказівки не зарезервоване для вказівки на помилку, програма, яка бажає перевірити наявність помилок, повинна встановити 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передбачає необхідне перетворення з латиниці-2 в UCS-2, оскільки дамп-з-іменами підключено лише з 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, але якщо англійський опис не доступний, але французький, то французький опис наводиться замість латинської-1. Однак, якщо змінна LANGUAGEабо LANGсередовище починається з літер 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 charmaps чи ні, використовує діаграму ASCII і більше нічого. Отже, це все, що я отримую. Якби я запустив його, не luitфільтруючи його, odповернув би його назад і знову надрукував би ту саму карту\0400.

Однак з вищевказаним методом є дві основні проблеми. По-перше, є порядок складання системи - для не-ASCII локалів значення укусів для діаграм не просто не залежать seq, що, як я думаю, є, ймовірно, серцем проблеми, яку ви намагаєтеся вирішити.

Ну, на tr's manсторінці GNU зазначено, що вона розширить [:upper:] [:lower:]класи по порядку - але це не багато.

Я думаю, що якесь важке рішення можна було б реалізувати, sortале це було б досить громіздким інструментом для API програмування бекенду.

recodeзробить це правильно, але ви не здавались занадто закоханим у програму днями. Можливо, сьогоднішні редагування на це будуть кидати більш привітне світло, а може й ні.

GNU також пропонує gettextбібліотеку функцій, і, здається, зможе вирішити цю проблему принаймні для LC_MESSAGESконтексту:

- Функція: char * bind_textdomain_codeset( const char *domainname, const char *codeset)

bind_textdomain_codesetФункція може бути використана для визначення набору символів для виведення каталогів повідомлень для домену ім'я_домена . Аргумент набору коду має бути дійсним набором коду, яке можна використовувати для функції iconv_open , або нульовим вказівником.

Якщо Codeset параметр є покажчиком NULL, 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термінальний ptyпристрій перекладу UTF-8, я думаю, що він працює між XTerms без підтримки UTF-8. Він обробляє безліч комутаторів - наприклад, реєстрацію всіх перетворених байтів у файл або -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які я задумливо прокручував, знаючи добре, що я також не змусив їх працювати.


1
Це все дуже приємна та корисна інформація, але це дає інформацію про вихідні файли (in i18n), які можуть бути, а можуть і не використовуватися для генерації локалі, який я зараз використовую. Інформація про локаль, ймовірно, надходить від /usr/lib/locale/locale-archiveабо /some/dir/LC_CTYPE, і це частина, що стосується мого локалу, яка зберігається у тих файлах, які я шукаю.
Стефан Шазелас

@StephaneChezales - тому просто витягніть свій LC_STUFFархів з архіву localedef- це теж зробить. Я можу також демонструвати це, я думаю. Ви можете також переглянути , що і майже все інше з stringsабо odабо будь-яким з решта. Я все одно. Але, до речі - charmaps є локаль Youre в даний час використовують - і localedefповідомить про те , що , як добре. Крім того, що recodeробить теж.
mikeserv

Ви в основному говорите, що ми можемо зробити вручну те, що бібліотеки системи робити, щоб запитувати інформацію про клас символів, але для цього надійно потрібно тисячі рядків коду, і результат буде специфічним для системи. (аналізує середовище так само, як це робить системна бібліотека (LOCPATH, LANG, LANGUAGE, LC_CTYPE ..., визначте, де шукати дані, витягнути їх ...). Я не можу зрозуміти, як витягти матеріали з архіву з localedef хоч.
Стефан Шазелас

@StephaneChazelas - Я не пропоную вам зробити це вручну - я пропоную вам зробити це за допомогою комп'ютера - з допомогою системних виконуваних файлів , таких як od, recode, uconvі все інше. Але це була моя помилка - це не localedefте, що це витягує, це те, recodeщо буде. Ви повинні перевірити info recode- і крім команди recodeтаблиці, яку я показую, є майже те саме - і я думаю, що вона буде обробляти речі таким же чином. Це не просто витягує ваш шафа з повітря. У будь-якому випадку я покладав великі надії на ці perlмодулі - ви спробували якісь?
mikeserv

1
Якщо є API для отримання списку символів у заданому класі символів у поточному мові, то саме це я шукаю. Якщо ви зможете продемонструвати, як це зробити, я прийму відповідь. Єдине, про що я міг придумати (і як я отримав "очікуваний результат" у своєму запитанні) - це використовувати iswblank(3)для всіх можливих значень символів.
Стефан Шазелас

1

Щонайменше в системах 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 для цього ІДЕОГРАФІЧНОГО ПРОСТОРУ). У той час як в EUCJP, це ті самі байти, але перемикання стану здійснюється перегортанням 8-го біта ( A1 = 21 | 0x80), що робить його більш без стану.

Це означає, що в цих кодованих стаціонарних кодуваннях є кілька способів записати заданий символ (наприклад, вставивши кілька цих послідовностей комутації стану ), а показана послідовність за цим кодом вище - лише один із них (канонічний з початкового стан за замовчуванням).

Хоча для нормальної мови, символи не можуть бути за межами 0..0xD7FF, 0xE000..0x10FFFF, для шахрайського локалу може бути будь-який символ у діапазоні, підтримуваний wchar_t. Наприклад, я можу створити локаль, де символи U + DCBA або U + 12345678 (або були символи, якби вони були дозволені) є порожніми . Ось чому ви хочете скласти цей код, -D SUPPORT_ROGUE_LOCALESщоб охопити їх, хоча це означає, що для сканування всього списку потрібно набагато більше часу.

Я не міг використовувати рішення @ mikeserv, оскільки recodeвикористовує власні перетворення, більше не підтримується і підтримує лише символи Unicode до 0xFFFF, і GNU trпринаймні не працює з багатобайтовими символами.

Я не міг використовувати @ ChrisDown, оскільки pythonне має інтерфейсів до класів символів POSIX.

Я спробував Perl, але це нечітко для кодових точок від 128 до 255 для багатобайтових локалів, відмінних від UTF-8, і не використовує бібліотеки перетворення системи.


Я думаю, що це фактично єдиний спосіб зробити це, але він страждає від декількох проблем, починаючи з того, що ви використовували попередні знання для вирішення кола законів. Принаймні теоретично, якщо ви використовуєте чарову карту Unicode, класи символів не залежать від сценарію (згідно стандарту Unicode, а не на локалі C), але "загальні категорії" Unicode не є такими ж, як класи символів C. BTW, у типів i18n glibc входять ще два класи символів: combiningі combining_level3(саме iswctype(i, wctype("combining")))
rici

@rici, див. редагування (а також питання).
Стефан Шазелас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.