Polecenie pobrania listy znaków z danej klasy znaków w bieżącym języku

18

Co może być sposobem, aby pobrać listę wszystkich znaków w danej klasy postaci (jak blank, alpha, digit...) w obecnej lokalizacji.

Na przykład,

LC_ALL=en_GB.UTF-8 that-command blank

idealnie, w moim systemie Debian, wyświetlałby coś takiego:

      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

A w lokalizacji C może wyświetlać się coś takiego:

09 U+0009 HORIZONTAL TAB
20 U+0020 SPACE

Oznacza to reprezentację znaku w ustawieniach narodowych pod względem tablic bajtów (takich jak UTF-8 w pierwszym przykładzie i pojedynczego bajtu w drugim), równoważny znak kodowy Unicode i opis.

Kontekst

(edytuj) Teraz, gdy luka została już łatana i ujawniona, mogę dodać trochę kontekstu.

Zadałem to pytanie w czasie, gdy badałem CVE 2014-0475 . glibcwystąpił błąd polegający na tym, że pozwala użytkownikowi na użycie takich ustawień LC_ALL=../../../../tmp/evil-localenarodowych w stosunku do standardowej ścieżki wyszukiwania ustawień regionalnych systemu, a tym samym pozwala na użycie dowolnego pliku jako definicji ustawień regionalnych.

Mógłbym stworzyć locale łobuz na przykład za pomocą jednego bajta na znak charset gdzie większość znaków wyjątkiem s, ha kilka innych zostało uznane półfabrykatów i która stałaby bashprowadzonym shpodczas parsowania typowy Debiana /etc/bash.bashrcplik (i które mogłyby być wykorzystane, aby uzyskać powłoki dostępu, na gitpod warunkiem, że serwer hostingowy bashjest używany jako powłoka logowania gitużytkownika serwera oraz że sshserwer akceptuje LC_*/ LANGzmienne i że osoba atakująca może przesyłać pliki na serwer).

Teraz, gdybym kiedykolwiek znalazł LC_CTYPE(skompilowaną definicję ustawień regionalnych), w /tmp/eviljaki sposób miałbym dowiedzieć się, że była to nieuczciwa metoda i w jaki sposób.

Moim celem jest więc dekompilacja definicji ustawień regionalnych, a jeśli nie, to przynajmniej wiem, które znaki (wraz z ich kodowaniem) należą do danej klasy znaków.

Mając to na uwadze:

  • Rozwiązania, które sprawdzają pliki źródłowe dla ustawień narodowych (definicje ustawień regionalnych, takie jak te w /usr/share/i18n/localeDebianie) nie są w moim przypadku przydatne.
  • Właściwości znaków Unicode są nieistotne. Dbam tylko o to, co mówi lokacja. W systemie Debian, nawet pomiędzy dwoma lokalizacjami systemu UTF-8, nie mówiąc już o fałszywych ustawieniach, lista znaków w klasie może być inna.
  • Narzędzia podoba recode, pythonalbo perlże zrobić bajtów / multi-bajt do / z konwersji znaków nie może być stosowany jako oni mogą (aw praktyce nie) dokonać konwersji w inny sposób niż lokalizacji.
Stéphane Chazelas
źródło
W większości ustawień narodowych ostatecznie pochodzi z LC_CTYPE w (z glibc) /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
derobert
@derobert, tak, podczas gdy locale(przynajmniej GNU) pobiera wiele informacji przechowywanych w wielu kategoriach, rzeczy, które nie są najważniejsze w LC_CTYPE i LC_COLLATE. Zastanawiam się, czy istnieje ukryty interfejs API do pobierania tych informacji lub dekompilacji informacji regionalnych.
Stéphane Chazelas
Tak - możesz parsować te informacje - w końcu zabrałem się za dokończenie edycji. Jest kilka poleceń, które prawdopodobnie już zainstalowałeś - przynajmniej tak zrobiłem i nawet o nich nie wiedziałem. Mam nadzieję, że to pomoże. W szczególności recodei uconvmoże dać ci to, co mówisz, że szukasz. Być może nawet luiti odchyba…
mikeserv
To jest bardzo dobre! To znaczy, że perlwcale nie potrzebujesz .
mikeserv
I wydaje się być w stanie w zasadzie wyodrębnić mój charset od LC_CTYPEz zaledwie od -A n -t c <LC_CTYPE | tsortPrawdopodobnie próbowałeś go już, ale nigdy nie słyszałem o tym wcześniej i byłem poprzez czytanie infoi przypomniało mi to - i wydaje się do pracy. Są też, ptxale myślę, że to mniej istotne. W każdym razie, jeśli nie wypróbowałeś go i zdecydowałeś się to zrobić - uczciwe ostrzeżenie - wymaga to trochę cierpliwości. lehman.cuny.edu/cgi-bin/man-cgi?tsort+1
mikeserv

Odpowiedzi:

7

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 odjako 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..dumpwygeneruje 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, recodedostarczy ci pełną mapę postaci. Zgodnie z jego instrukcją robi to najpierw zgodnie z bieżącą wartością DEFAULT_CHARSETzmiennej ś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_CHARSETzostanie użyta wartość zmiennej w środowisku. Jeśli ta zmienna nie jest zdefiniowana, recodebiblioteka 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, LANGi można ją ustalić za pomocą polecenialocale charmap.

Warto również zauważyć recode, że jest to interfejs API :

Nazwany program recodejest 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 recodeprogramem.

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 POSIXi Cdefiniują strcoll()funkcję:

strcoll()Funkcja porównują łańcuch wskazywany przez s1się łańcuch wskazywany przez s2zaró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 POSIXklasy postaci, już zauważyłeś, że użyłeś CAPI, 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 < inputoznacza konieczną konwersję z Latin-2 na UCS-2, ponieważ zrzut z nazwami jest podłączony tylko z UCS-2. W takich przypadkach recodenie 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 LANGUAGElub LANGzaczyna 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 recodenajwyraź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 luitfiltrowania, ododwró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 seqważne, co, jak sądzę, jest prawdopodobnie rdzeniem problemu, który próbujesz rozwiązać.

Cóż, tr's manstrona 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, sortale byłoby to raczej niewygodne narzędzie do API programowania zaplecza.

recodezrobi 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ż gettextbibliotekę funkcji i wydaje się, że jest w stanie rozwiązać ten problem przynajmniej w LC_MESSAGESkontekście:

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

Za pomocą tej bind_textdomain_codesetfunkcji 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_codesetfunkcji 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_codesetFunkcja 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 abez 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+0300do 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 Tclwł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_COLLATEsam 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, localedefjak 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ć copypolecenia na całej liście. Powyższy plik wydaje się na przykład copyw „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 grepoczywiś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ż luitterminalowe ptyurzą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 -cjako prosty |pipefiltr.

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 3powią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 Xlibfunkcje obsługi to cały czas - luitjest częścią tego pakietu.

Te Tcl_uni...funkcje mogą okazać się przydatne również.

tylko trochę <tab>ukończenia i manposzukiwań i nauczyłem się sporo na ten temat.

Za pomocą localedef- możesz skompilować localesw swoim I18Nkatalogu. Dane wyjściowe są funky i nie są wyjątkowo przydatne - wcale nie tak jak charmapsw 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 odmoż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 odjest 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 Perli nie wiem, jak poprawnie załadować moduł. Ale manstrony 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, I18Nktóre tęsknie przewinąłem, wiedząc dobrze, że ich też nie sprawię.

mikeserv
źródło
1
To wszystko bardzo miłe i przydatne informacje, ale daje to informacje o plikach źródłowych (wewnątrz i18n), które mogły zostać użyte w celu wygenerowania ustawień regionalnych, których aktualnie używam. Informacje o ustawieniach regionalnych prawdopodobnie pochodzą z /usr/lib/locale/locale-archivelub /some/dir/LC_CTYPE, i to jest część związana z moimi ustawieniami regionalnymi, która jest przechowywana w plikach, których szukam.
Stéphane Chazelas
@StephaneChezales - więc po prostu wypakuj swoje LC_STUFFarchiwum za pomocą localedef- robi to również. Myślę, że mogę to również pokazać. Można również zobaczyć, że i prawie wszystko inne z stringslub odlub którykolwiek z pozostałych. W każdym razie tak zrobiłem. Ale nawiasem mówiąc - charmaps to ustawienia regionalne, których obecnie używasz - i localedefrównież o tym poinformują. Też to recoderobi.
mikeserv
Mówisz w zasadzie, że możemy zrobić ręcznie to, co biblioteki systemowe wykonują w zapytaniach o informacje o klasie znaków, ale to będzie wymagać tysięcy wierszy kodu, aby zrobić to niezawodnie, a wynik będzie specyficzny dla systemu. (analizowanie środowiska w taki sam sposób, jak biblioteka systemowa (LOCPATH, LANG, LANGUAGE, LC_CTYPE ..., określanie, gdzie szukać danych, wyodrębnianie ich ...). Nie widzę, jak wyodrębnić rzeczy z archiwum z localedef
Stéphane Chazelas
@StephaneChazelas - Nie sugeruję zrobić to ręcznie - Proponuję zrobić z komputera - za pomocą systemu plików binarnych, takich jak od, recode, uconvi reszta. Ale to był mój błąd - to nie tak, localedefże to wyciąga, tylko to recodezrobi. Musisz to sprawdzić info recode- i oprócz recodepolecenia tabeli pokazuję, że jest bardzo to samo - i myślę, że poradzi sobie w ten sam sposób. Nie tylko wyciąga twój zestaw z cienkiego powietrza. W każdym razie miałem duże nadzieje na te perlmoduły - wypróbowałeś coś takiego?
mikeserv
1
Jeśli istnieje interfejs API do pobierania listy znaków w danej klasie znaków w bieżących ustawieniach narodowych, właśnie tego właśnie szukam. Jeśli potrafisz pokazać, jak to zrobić, zaakceptuję odpowiedź. Jedyne, co mogłem wymyślić (i jak uzyskałem „oczekiwany wynik” w moim pytaniu), to użycie iswblank(3)wszystkich możliwych wartości postaci.
Stéphane Chazelas
1

W systemach GNU, FreeBSD lub Solaris to brutalne podejście działa:

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

Chociaż dla C / POSIX wchar_tjest nieprzejrzystym typem, który nie ma związku z Unicode i gwarantuje jedynie, że obejmie wszystkie znaki obsługiwane przez ustawienia regionalne systemu, w praktyce w większości systemów obsługujących Unicode, wartości odpowiadają punktom kodu Unicode a same definicje ustawień regionalnych są oparte na Unicode.

Unicode ma być nadzbiorem wszystkich znanych zestawów znaków, więc zapętlanie wszystkich prawidłowych punktów kodu w Unicode (od 0 do 0xD7FF i 0xE000 do 0x10FFFF) powinno zawierać przynajmniej wszystkie znaki obsługiwane przez dany zestaw znaków.

W tym przypadku używamy standardowego interfejsu API ustawień regionalnych systemu, aby sprawdzić, które z nich są danego typu i przekonwertować go na postać zakodowaną w kodowaniu ustawień regionalnych. Używamy perli jego charnamesmodułu tylko, aby uzyskać nazwę z danego punktu kodowego Unicode.

W lokalizacjach korzystających z kodowania stanowego, takich jak ISO-2022-JP, upewniamy się, że zakodowana forma jest wyświetlana z domyślnego stanu początkowego.

Nie znalazłem systemu, w którym zainstalowano ustawienia regionalne ze stanowym kodowaniem znaków, ale przynajmniej w systemach GNU można wygenerować takie, aby można było wprowadzić nieuczciwe ustawienia regionalne (a przynajmniej narzędzia GNU nie działają poprawnie w tych systemach lokalizacje). Na przykład z niestandardowymi ustawieniami narodowymi używającymi ISO-2022-JP ze zwykłymi ja_JPustawieniami narodowymi otrzymuję:

$ 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

Porównać z:

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

W ISO-2022-JP 1B 24 42sekwencja ( \e$B) przełącza się z ASCII do stanu, w którym znaki są wyrażane jako 2 (7-bitowe) bajty (tutaj 21 21 dla tej PRZESTRZENI IDEOGRAFICZNEJ). W EUCJP są to te same bajty, ale przełączanie stanu odbywa się poprzez odwrócenie ósmego bitu ( A1 = 21 | 0x80), co czyni go bardziej bezstanowym.

Oznacza to, że w tych stanowych kodowaniach istnieje kilka sposobów na napisanie danego znaku (na przykład poprzez wstawienie kilku z tych sekwencji przełączających stan ), a pokazana sekwencja według tego kodu powyżej jest tylko jednym z nich (kanoniczna od początku stan domyślny).

Podczas gdy w normalnych ustawieniach narodowych znaki nie mogą znajdować się poza 0..0xD7FF, 0xE000..0x10FFFF, w przypadku nieuczciwych ustawień regionalnych dowolna postać z zakresu obsługiwanego przez wchar_t może być. Na przykład mogę utworzyć ustawienia narodowe, w których znaki U + DCBA lub U + 12345678 (lub byłyby znakami, jeśli byłyby dozwolone) byłyby spacjami . Dlatego chcesz skompilować ten kod, -D SUPPORT_ROGUE_LOCALESaby je uwzględnić, ale oznacza to, że skanowanie całej listy zajmuje dużo więcej czasu.

Nie mogłem użyć rozwiązania @ mikeserv, ponieważ recodeużywa własnych konwersji, nie jest już obsługiwane i obsługuje tylko znaki Unicode do 0xFFFF, a GNU trprzynajmniej nie działa ze znakami wielobajtowymi.

Nie mogłem użyć @ ChrisDown, ponieważ pythonnie ma interfejsów do klas znaków POSIX.

Próbowałem Perla, ale jest fałszywy dla punktów kodowych od 128 do 255 dla wielobajtowych ustawień narodowych innych niż UTF-8 i nie korzysta z bibliotek konwersji systemu.

Stéphane Chazelas
źródło
Myślę, że jest to faktycznie jedyny sposób, aby to zrobić, ale ma kilka problemów, zaczynając od tego, że wykorzystałeś wcześniejszą wiedzę, aby zdecydować o zakresie legalnych współrzędnych kodowych. Teoretycznie przynajmniej, jeśli używasz Charmap Unicode, klasy znaków są niezależne od skryptu (zgodnie ze standardem Unicode, a nie lokalizacjami C), ale „ogólne kategorie” Unicode też nie są takie same jak klasy znaków C. BTW, combiningcombining_level3iswctype(i, wctype("combining"))
typy c18 ili w
@rici, patrz edycja (a także pytanie).
Stéphane Chazelas