ВОЗМОЖНОЕ ЗАКЛЮЧИТЕЛЬНОЕ РЕШЕНИЕ
Итак, я взял всю нижеприведенную информацию и придумал это:
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
является просто приложением своей библиотеки перекодирования. Библиотека перекодировки доступна отдельно для других программ на Си. Хороший способ познакомиться с библиотекой перекодирования - познакомиться с самой recode
программой.
Чтобы использовать библиотеку перекодирования после ее установки, программе на Си должна быть строка:
#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
классов персонажей, вы уже отметили, что использовали C
API, чтобы найти их. Для символов и классов Юникода вы можете использовать кодировку recode's
dump-with-names для получения желаемого результата. Из руководства снова :
Например, команда recode l2..full < input
подразумевает необходимое преобразование из Latin-2 в UCS-2, так как dump-with-names подключен только из UCS-2. В таких случаях recode
не отображаются исходные
коды Latin-2 в дампе, только соответствующие значения UCS-2 . Чтобы дать более простой пример, команда
echo 'Hello, world!' | recode us..dump
производит следующий вывод:
UCS2 Mne Description
0048 H latin capital letter h
0065 e latin small letter e
006C l latin small letter l
006C l latin small letter l
006F o latin small letter o
002C , comma
0020 SP space
0077 w latin small letter w
006F o latin small letter o
0072 r latin small letter r
006C l latin small letter l
0064 d latin small letter d
0021 ! exclamation mark
000A LF line feed (lf)
Описательный комментарий дается на английском языке и в кодировке ASCII, но если описание на английском языке недоступно, а описание на французском - вместо этого приводится описание на французском языке с использованием Latin-1. Однако, если
переменная окружения LANGUAGE
or 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 или нет, использует кодировку 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
Функция может быть использована для определения набора символов для вывода каталогов сообщений для домена
имя_домена . Codeset аргумент должен быть допустимым Codeset именем , которое может быть использовано для iconv_open функции или указателя нулевого.
Если параметр codeset является нулевым указателем, bind_textdomain_codeset
возвращает текущий выбранный кодовый набор для домена с именем
domainname . Возвращает 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
которые я задумчиво прокручивал, прекрасно зная, что я не заставлю их работать.
/usr/share/i18n/locales/i18n
... который, конечно же, в основном из базы данных символов Unicode. Конечно, было бы неплохо иметь команду