MOŻLIWE ROZWIĄZANIE KOŃCOWE
Więc wziąłem wszystkie poniższe informacje i przedstawiłem to:
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
UWAGA :
Używam od
jako ostatniego filtru dla preferencji i ponieważ wiem, że nie będę pracował ze znakami wielobajtowymi, które nie będą poprawnie obsługiwane. recode u2..dump
wygeneruje wyjście bardziej podobne do określonego w pytaniu i poprawnie obsłuży szerokie znaki.
WYNIK
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 PROGRAMATORA
Jak pokażę poniżej, recode
dostarczy ci pełną mapę postaci. Zgodnie z jego instrukcją robi to najpierw zgodnie z bieżącą wartością DEFAULT_CHARSET
zmiennej środowiskowej lub, jeśli to nie działa, działa dokładnie tak, jak określono:
Jeśli nazwa zestawu znaków zostanie pominięta lub pozostawiona pusta, DEFAULT_CHARSET
zostanie użyta wartość zmiennej w środowisku. Jeśli ta zmienna nie jest zdefiniowana, recode
biblioteka używa kodowania bieżącego ustawienia narodowego. W systemach zgodnych z POSIX zależy to od pierwszej niepustej wartości spośród zmiennych środowiskowych LC_ALL, LC_CTYPE, LANG
i można ją ustalić za pomocą polecenialocale charmap.
Warto również zauważyć recode
, że jest to interfejs API :
Nazwany program recode
jest tylko aplikacją biblioteki do przekodowywania. Biblioteka przekodowywania jest dostępna osobno dla innych programów C. Dobrym sposobem na zaznajomienie się z biblioteką przekodowywania jest zapoznanie się z samym recode
programem.
Aby użyć biblioteki przekodowywania po zainstalowaniu, program C musi mieć wiersz:
#include <recode.h>
Do porównywania ciągów przyjaznych na arenie międzynarodowej Standardy POSIX
i C
definiują strcoll()
funkcję:
strcoll()
Funkcja porównują łańcuch wskazywany przez s1
się łańcuch wskazywany przez s2
zarówno interpretować jako właściwe dla danej kategorii LC_COLLATE bieżącej lokalizacji.
strcoll()
Funkcja nie powinna zmienić ustawienie errno jeśli się powiedzie.
Ponieważ żadna wartość zwrotna nie jest zarezerwowana do wskazania błędu, aplikacja chcąca sprawdzić, czy występują błędy, powinna ustawić wartość errno na 0, a następnie wywołać
strcoll()
, a następnie sprawdzić wartość errno.
Oto osobno umieszczony przykład jego użycia:
#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);
}
Jeśli chodzi o POSIX
klasy postaci, już zauważyłeś, że użyłeś C
API, aby je znaleźć. W przypadku znaków i klas Unicode możesz użyć zestawu znaków recode's
zrzutu z nazwami, aby uzyskać pożądany wynik. Z instrukcji ponownie :
Na przykład polecenie recode l2..full < input
oznacza konieczną konwersję z Latin-2 na UCS-2, ponieważ zrzut z nazwami jest podłączony tylko z UCS-2. W takich przypadkach recode
nie wyświetla oryginalnych
kodów Latin-2 na zrzucie, tylko odpowiednie wartości UCS-2 . Aby dać prostszy przykład, polecenie
echo 'Hello, world!' | recode us..dump
produkuje następujące dane wyjściowe:
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)
Komentarz opisowy jest podany w języku angielskim i ASCII, ale jeśli opis w języku angielskim nie jest dostępny, ale opis w języku francuskim jest, to zamiast tego opis w języku francuskim jest podawany za pomocą Latin-1. Jeśli jednak
zmienna środowiskowa LANGUAGE
lub LANG
zaczyna się od liter fr , wówczas preferencje wyświetlania są wybierane w języku francuskim, gdy oba opisy są dostępne.
Używając podobnej składni do powyższej w połączeniu z dołączonym testowym zestawem danych , mogę uzyskać własną mapę znaków za pomocą:
recode -q u8/test8..dump </dev/null
WYNIK
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)
Ale dla zwykłych postaci recode
najwyraźniej nie jest to konieczne. To powinno dać ci nazwane znaki dla wszystkiego w 128-bajtowym zestawie znaków:
printf %b "$(printf \\%04o $(seq 128))" |
luit -c |
od -A n -t o1z -t a -w12
WYNIK
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
Oczywiście reprezentowanych jest tylko 128 bajtów, ale to dlatego, że moje ustawienia regionalne, charmapy utf-8 lub nie, używają zestawu znaków ASCII i nic więcej. To wszystko, co dostaję. Gdybym jednak uruchomił go bez luit
filtrowania, od
odwróciłbym go i wydrukowałbym ponownie tę samą mapę\0400.
Istnieją jednak dwa główne problemy z powyższą metodą. Po pierwsze, kolejność sortowania w systemie - w przypadku lokalizacji innych niż ASCII wartości zgryzu dla zestawów znaków nie są po prostu seq
ważne, co, jak sądzę, jest prawdopodobnie rdzeniem problemu, który próbujesz rozwiązać.
Cóż, tr's man
strona GNU stwierdza, że będzie rozwijała [:upper:]
[:lower:]
klasy w kolejności - ale to niewiele.
Wyobrażam sobie, że można zaimplementować jakieś ciężkie rozwiązanie, sort
ale byłoby to raczej niewygodne narzędzie do API programowania zaplecza.
recode
zrobi to poprawnie, ale któregoś dnia nie zakochałeś się w programie. Może dzisiejsze zmiany rzucą na to bardziej przyjazne światło, a może nie.
GNU oferuje również gettext
bibliotekę funkcji i wydaje się, że jest w stanie rozwiązać ten problem przynajmniej w LC_MESSAGES
kontekście:
- Funkcja: char * bind_textdomain_codeset
( const char *domainname,
const char *codeset
)
Za pomocą tej bind_textdomain_codeset
funkcji można określić wyjściowy zestaw znaków dla katalogów komunikatów dla domeny
nazwa_domeny . Zestaw kodów argument musi być ważny zestaw kodów imię, które mogą być wykorzystane do iconv_open funkcji lub wskaźnikiem NULL.
Jeśli parametrem zestawu kodów jest wskaźnik zerowy, bind_textdomain_codeset
zwraca aktualnie wybrany zestaw kodów dla domeny o nazwie
nazwa_domeny . Zwraca NULL, jeśli nie wybrano jeszcze żadnego zestawu kodów .
Z tej bind_textdomain_codeset
funkcji można korzystać kilka razy. W przypadku wielokrotnego użycia z tym samym argumentem nazwy domeny późniejsze wywołanie zastępuje ustawienia wcześniejszego.
bind_textdomain_codeset
Funkcja zwraca wskaźnik do łańcucha znaków zawierającego nazwę wybranego zestawu znaków. Ciąg jest przydzielany wewnętrznie w funkcji i nie może być zmieniany przez użytkownika. Jeśli system wyszedł z rdzenia podczas wykonywania
bind_textdomain_codeset
, zwracana wartość to NULL i odpowiednio ustawiana jest zmienna globalna errno.
Możesz także użyć rodzimych kategorii znaków Unicode , które są niezależne od języka i całkowicie rezygnują z klas POSIX, lub być może w celu wywołania pierwszej z nich, aby dostarczyć ci informacji wystarczających do zdefiniowania drugiej.
Oprócz komplikacji Unicode zapewnia także nowe możliwości. Jednym z nich jest to, że każdy znak Unicode należy do określonej kategorii. Możesz dopasować pojedynczy znak należący do kategorii „litera” z
\p{L}
. Możesz dopasować pojedynczy znak nienależący do tej kategorii \P{L}
.
Znów „znak” naprawdę oznacza „punkt kodowy Unicode”. \p{L}
dopasowuje pojedynczy punkt kodowy w kategorii „litera”. Jeśli łańcuch wejściowy jest à
zakodowany jako U+0061 U+0300
, pasuje a
bez akcentu. Jeśli wejście jest à
zakodowane jako U+00E0
, pasuje à
do akcentu. Powodem jest to, że oba kody wskazują U+0061 (a)
i U+00E0 (à)
należą do kategorii „litera”, podczas gdy U+0300
do kategorii „znak”.
Powinieneś teraz zrozumieć, dlaczego \P{M}\p{M}*+
jest to odpowiednik \X
.
\P{M}
dopasowuje punkt kodowy, który nie jest znakiem łączącym, a \p{M}*+
dopasowuje zero lub więcej punktów kodowych, które łączą znaki. Aby dopasować literę, w tym wszelkie znaki diakrytyczne, użyj \p{L}\p{M}*+
. To ostatnie wyrażenie zawsze będzie pasować à
, niezależnie od tego, w jaki sposób jest zakodowane. Kwantyfikator dzierżawczy dba o to, aby powrót nie spowodował \P{M}\p{M}*+
dopasowania znaku nie będącego znakiem bez łączących znaków, które następują po nim, co \X
nigdy by się nie udało .
Ta sama witryna internetowa, która zawiera powyższe informacje, omawia także Tcl
własną implementację wyrażeń regularnych zgodną z POSIX, która może być kolejnym sposobem na osiągnięcie celu.
I na koniec wśród rozwiązań zasugeruję, że możesz przesłuchać LC_COLLATE
sam plik w celu uzyskania kompletnej i uporządkowanej systemowej mapy znaków. Może się to wydawać trudne, ale po skompilowaniu go osiągnąłem sukces, localedef
jak pokazano poniżej:
<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
Jest to wprawdzie obecnie wadliwe, ale mam nadzieję, że to pokazuje przynajmniej taką możliwość.
NA PIERWSZY RÓŻ
strings $_/en_GB
#OUTPUT
int_select "<U0030><U0030>"
...
END LC_TELEPHONE
To naprawdę nie wyglądało dużo, ale potem zacząłem zauważać copy
polecenia na całej liście. Powyższy plik wydaje się na przykład copy
w „en_US” , a innym naprawdę dużym, który wydaje się, że wszyscy w pewnym stopniu się nim dzielą iso_14651_t1_common
.
Jest dość duży:
strings $_ | wc -c
#OUTPUT
431545
Oto wprowadzenie do /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>;
...
Możesz grep
oczywiście to zrobić, ale możesz po prostu:
recode -lf gb
Zamiast. Dostałbyś coś takiego:
Dec Oct Hex UCS2 Mne BS_4730
0 000 00 0000 NU null (nul)
1 001 01 0001 SH start of heading (soh)
...
... I WIĘCEJ
Wydaje mi się, że jest też luit
terminalowe pty
urządzenie tłumaczące UTF-8 , które działa pośrednio w XTerms bez obsługi UTF-8. Obsługuje wiele przełączników - takich jak rejestrowanie wszystkich przekonwertowanych bajtów do pliku lub -c
jako prosty |pipe
filtr.
Nigdy nie zdawałem sobie sprawy, że było tak wiele - lokalizacje i mapy postaci i tak dalej. To najwyraźniej bardzo ważna sprawa, ale myślę, że wszystko dzieje się za kulisami. Istnieje - przynajmniej w moim systemie - kilkaset man 3
powiązanych wyników dla wyszukiwań związanych z ustawieniami regionalnymi.
A także jest:
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
...
Trwa to bardzo długo.
Te Xlib
funkcje obsługi to cały czas - luit
jest częścią tego pakietu.
Te Tcl_uni...
funkcje mogą okazać się przydatne również.
tylko trochę <tab>
ukończenia i man
poszukiwań i nauczyłem się sporo na ten temat.
Za pomocą localedef
- możesz skompilować locales
w swoim I18N
katalogu. Dane wyjściowe są funky i nie są wyjątkowo przydatne - wcale nie tak jak charmaps
w ogóle - ale możesz uzyskać format raw tak, jak określiłeś powyżej, tak jak ja:
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
Następnie od
możesz przeczytać - bajty i ciągi:
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...<
...
Mimo że daleko mu do wygrania konkursu piękności, jest to użyteczny efekt. I od
jest konfigurowalna, jak chcesz go mieć, a także, oczywiście.
Chyba też o nich zapomniałem:
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
Prawdopodobnie o nich zapomniałem, ponieważ nie mogłem zmusić ich do pracy. Nigdy nie używam Perl
i nie wiem, jak poprawnie załadować moduł. Ale man
strony wyglądają całkiem nieźle. W każdym razie coś mówi mi, że wywołanie modułu Perla jest co najmniej trochę trudniejsze niż ja. I znowu, były już na moim komputerze - i nigdy nawet nie używam Perla. Jest też kilka takich, I18N
które tęsknie przewinąłem, wiedząc dobrze, że ich też nie sprawię.
/usr/share/i18n/locales/i18n
... który oczywiście pochodzi głównie z bazy znaków znaków Unicode. Oczywiście byłoby miło mieć polecenie