Команда для получения списка символов в заданном классе символов в текущей локали

Команда для получения списка символов в заданном классе символов в текущей локали

Какой может быть способ получить список всех символов в заданном классе символов (например 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, которые выполняют преобразование байтовых/многобайтовых символов в/из символов, использовать нельзя, поскольку они могут (и на практике делают это) выполнять преобразование не так, как предусмотрено локалью.

решение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.

Также стоит отметить recode, что этоэто API:

Названная программа recode— это просто приложение ее библиотеки перекодирования. Библиотека перекодирования доступна отдельно для других программ на языке C. Хороший способ познакомиться с библиотекой перекодирования — это ознакомиться с recodeсамой программой.

Чтобы использовать библиотеку перекодирования после ее установки, программа на языке C должна иметь строку:

#include <recode.h>

Для международного сравнения строк POSIXстандарты Cопределяютstrcoll()функция:

Функция strcoll()сравнивает строку, на которую указывает , s1со строкой, на которую указывает s2, при этом обе строки интерпретируются как соответствующие категории 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 дамп-с-именамиcharset для получения желаемого вывода. Из егоснова руководство:

Например, команда recode l2..full < inputподразумевает необходимое преобразование изЛатинский-2кУКС-2,какдамп-с-именамиподключен только изУКС-2.В таких случаях recodeне отображает оригинал Латинский-2коды в дампе, только соответствующиеУКС-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карты или нет, используетASCIIcharset и ничего больше. Так что это все, что я получаю. Если бы я запустил его без luitфильтрации, odто откатил бы его назад и снова напечатал бы ту же карту до\0400.

Однако с вышеприведенным методом связаны две основные проблемы. Во-первых, это порядок сортировки системы — для локалей, отличных от ASCII, значения байтов для наборов символов не просто влияют seq, что, как я думаю, скорее всего, является ядром проблемы, которую вы пытаетесь решить.

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

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

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

GNU также предлагает gettextбиблиотеку функций, и, кажется, она способнарешить эту проблемупо крайней мере для LC_MESSAGESконтекста:

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

Функцию bind_textdomain_codesetможно использовать для указания выходного набора символов для каталогов сообщений для домена. доменное имя.набор кодоваргумент должен быть действительнымнабор кодовимя, которое может быть использовано длязначокv_openфункция или нулевой указатель.

Еслинабор кодовпараметр — нулевой указатель, bind_textdomain_codeset возвращает текущий выбранныйнабор кодовдля домена с именем доменное имя. Возвращает NULL, если нетнабор кодовпока не выбран.

Функцию bind_textdomain_codesetможно использовать несколько раз. Если использовать ее несколько раз с одним и тем же аргументом domainname, то более поздний вызов переопределяет настройки, сделанные предыдущим.

Функция bind_textdomain_codesetвозвращает указатель на строку, содержащую имя выбранного кодового набора. Строка выделяется внутри функции и не должна изменяться пользователем. Если система вышла из ядра во время выполнения bind_textdomain_codeset, возвращаемое значение равно NULL, а глобальная переменная errno устанавливается соответствующим образом.

Вы также можете использовать родной языксимвол Юникодакатегории, которые не зависят от языка и полностью отказываются от классов 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в"ru_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-8, ptyкоторое, как я полагаю, действует как посредник для 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которые я с тоской прокрутил, прекрасно понимая, что я тоже не заставлю их работать.

решение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-битные) байта (здесь 21 21 для этого ИДЕОГРАФИЧЕСКОГО ПРОСТРАНСТВА). В то время как в EUCJP это те же байты, нопереключение состоянийделается путем переворачивания 8-го бита ( A1 = 21 | 0x80), что делает его более безызносным.

Это означает, что в этих кодировках с сохранением состояния существует несколько способов записи заданного символа (например, путем вставки нескольких из них)переключение состоянийпоследовательности), и показанная последовательность в этом коде выше является лишь одной из них (канонической из начального состояния по умолчанию).

В то время как для обычной локали символы не могут находиться за пределами 0..0xD7FF, 0xE000..0x10FFFF, длянегодяйlocale, любой символ в диапазоне, поддерживаемом wchar_t, может быть. Например, я мог бы создать locale, где символы U+DCBA или U+12345678 (или были бы символами, если бы они были разрешены) являютсяпробелы. Вот почему вам нужно скомпилировать этот код, чтобы -D SUPPORT_ROGUE_LOCALESохватить их, хотя это означает, что потребуется гораздо больше времени для сканирования всего списка.

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

Я не мог использовать@ChrisDown'sне pythonимеет интерфейсов к классам символов POSIX.

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

Связанный контент