Comando per recuperare l'elenco di caratteri in una determinata classe di caratteri nella locale corrente


18

Quale potrebbe essere un modo per recuperare un elenco di tutti i personaggi in una determinata classe di caratteri (come blank, alpha, digit...) nella localizzazione corrente.

Per esempio,

LC_ALL=en_GB.UTF-8 that-command blank

idealmente, sul mio sistema Debian, verrebbe visualizzato qualcosa del tipo:

      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

E nella locale C potrebbe essere visualizzato qualcosa del tipo:

09 U+0009 HORIZONTAL TAB
20 U+0020 SPACE

Cioè, la rappresentazione del carattere nella locale in termini di matrici di byte (come UTF-8 nel primo esempio e singolo byte nel secondo), il punto di codice equivalente del carattere Unicode e una descrizione.

Contesto

(modifica) Ora che la vulnerabilità è stata a lungo modificata e divulgata, posso aggiungere un po 'di contesto.

Ho fatto quella domanda mentre stavo indagando su CVE 2014-0475 . glibcpresentava un bug in quanto consentiva all'utente di utilizzare impostazioni locali del genere LC_ALL=../../../../tmp/evil-localeche venivano risolte in relazione al percorso di ricerca delle impostazioni internazionali del sistema standard e quindi consentivano di utilizzare qualsiasi file come definizione delle impostazioni locali.

Potrei creare una localizzazione errata per esempio con un singolo byte per carattere set di caratteri in cui la maggior parte dei caratteri tranne s, he alcuni altri erano considerati vuoti e che sarebbero stati basheseguiti shmentre analizzava un tipico /etc/bash.bashrcfile Debian (e che poteva essere usato per ottenere l'accesso alla shell su un gitil server di hosting fornito, ad esempio, bashviene utilizzato come shell di accesso gitdell'utente del server e che il sshserver accetta LC_*/ LANGvariabili e che l'utente malintenzionato può caricare file sul server).

Ora, se mai trovassi una LC_CTYPE(compilata definizione locale) in /tmp/evil, come avrei scoperto che era una canaglia e in che modo.

Quindi il mio obiettivo è quello di non compilare quella definizione di locale e, in caso contrario, almeno sapere quale personaggio (insieme alla loro codifica) si trova in una determinata classe di caratteri.

Quindi con questo in mente:

  • Le soluzioni che guardano i file sorgente per le impostazioni locali (le definizioni delle impostazioni locali come quelle /usr/share/i18n/localesu Debian) non sono di alcun aiuto nel mio caso.
  • Le proprietà dei caratteri Unicode sono irrilevanti. Mi interessa solo quello che dice la locale. Su un sistema Debian, anche tra due locali di sistema UTF-8, figuriamoci quelli locali, l'elenco dei personaggi in una classe può essere diverso.
  • Strumenti come recode, pythono perlche fanno il byte / multi-byte da / per conversione dei caratteri non possono essere utilizzati in quanto potrebbero (e in pratica non) effettuare la conversione in modo diverso rispetto al locale.

Per la maggior parte dei locali alla fine proviene dal materiale LC_CTYPE in (con glibc) /usr/share/i18n/locales/i18n... che ovviamente proviene in gran parte dal database dei caratteri Unicode. Certo, sarebbe bello avere un comando
derobert

@derobert, sì, mentre locale(almeno quello GNU) recupera molte delle informazioni memorizzate in molte delle categorie, cose che non sono le più importanti in LC_CTYPE e LC_COLLATE. Mi chiedo se ci sia un'API nascosta per recuperare tali informazioni o per decomprimere le informazioni sulla locale.
Stéphane Chazelas,

Sì, puoi analizzare quelle informazioni. Sono finalmente riuscito a concludere la modifica. Ci sono molti comandi che probabilmente hai già installato - almeno l'ho fatto e non li sapevo nemmeno. Spero possa essere d'aiuto. In particolare recodee uconvpuò darti quello che dici quello che stai cercando. Forse anche solo luite odimmagino ...
Mikeserv,

È molto buono! Ciò significa che non è necessario perl, penso.
Mikeserv,

Mi sembra di essere in grado di estrarre sostanzialmente il mio set di caratteri LC_CTYPEcon od -A n -t c <LC_CTYPE | tsortProbabilmente l'hai già provato, ma non ne avevo mai sentito parlare prima e stavo leggendo infoe mi ha ricordato di questo - e sembra funzionare. C'è anche ptxma penso che sia meno rilevante. Ad ogni modo, se non l'hai provato e decidi di farlo - un avvertimento equo - richiede un po 'di pazienza. lehman.cuny.edu/cgi-bin/man-cgi?tsort+1
mikeserv

Risposte:


7

POSSIBILE SOLUZIONE FINALE

Quindi ho preso tutte le informazioni di seguito e ho escogitato questo:

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

NOTA :

Uso odcome filtro finale sopra per preferenza e perché so che non lavorerò con caratteri multi-byte, che non gestirà correttamente. recode u2..dumpgenererà entrambi un output più simile a quello specificato nella domanda e gestirà correttamente i caratteri di grandi dimensioni.

PRODUZIONE

        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 DEL PROGRAMMATORE

Come dimostrerò di seguito, recodeti fornirà la tua mappa completa dei personaggi. Secondo il suo manuale, lo fa in base al valore corrente della DEFAULT_CHARSETvariabile d'ambiente o, in mancanza, funziona esattamente come specificato:

Quando un nome di set di caratteri viene omesso o lasciato vuoto, DEFAULT_CHARSETviene invece utilizzato il valore della variabile nell'ambiente. Se questa variabile non è definita, la recodelibreria utilizza la codifica della locale corrente. Sui sistemi compatibili con POSIX , questo dipende dal primo valore non vuoto tra le variabili di ambiente LC_ALL, LC_CTYPE, LANGe può essere determinato tramite il comandolocale charmap.

Vale anche la pena notare recodeche è un api :

Il programma denominato recodeè solo un'applicazione della sua libreria di ricodifica. La libreria di ricodifica è disponibile separatamente per altri programmi C. Un buon modo per acquisire familiarità con la libreria di ricodifica è familiarizzare con il recodeprogramma stesso.

Per utilizzare la libreria di ricodifica una volta installata, un programma C deve avere una riga:

#include <recode.h>

Per un confronto di stringhe a livello internazionale Gli standard POSIXe Cdefiniscono la strcoll()funzione:

La strcoll()funzione deve confrontare la stringa puntata da s1con la stringa puntata da s2, entrambe interpretate come appropriate alla categoria LC_COLLATE della locale corrente.

La strcoll()funzione non deve modificare l'impostazione di errno in caso di successo.

Poiché nessun valore di ritorno è riservato per indicare un errore, un'applicazione che desidera verificare la presenza di situazioni di errore dovrebbe impostare errno su 0, quindi chiamare strcoll(), quindi controllare errno.

Ecco un esempio separato del suo utilizzo:

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

Per quanto riguarda le POSIXclassi di personaggi, hai già notato che hai utilizzato l' CAPI per trovarle. Per caratteri e classi unicode puoi usare recode's dump-with-names set di per ottenere l'output desiderato. Dal suo manuale di nuovo :

Ad esempio, il comando recode l2..full < inputimplica una conversione necessaria da Latin-2 a UCS-2, poiché il dump-with-names è collegato solo da UCS-2. In tali casi, recodenon visualizza i codici Latin-2 originali nel dump, ma solo i corrispondenti valori UCS-2 . Per dare un esempio più semplice, il comando

 echo 'Hello, world!' | recode us..dump

produce il seguente output:

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)

Il commento descrittivo è dato in inglese e ASCII, ma se la descrizione inglese non è disponibile ma è francese, allora viene data la descrizione francese usando Latin-1. Tuttavia, se la variabile di ambiente LANGUAGEo LANGinizia con le lettere fr , l'elenco delle preferenze passa al francese quando sono disponibili entrambe le descrizioni.

Utilizzando una sintassi simile a quella sopra combinata con il set di dati di test incluso, posso ottenere la mia mappa dei caratteri con:

recode -q u8/test8..dump </dev/null

PRODUZIONE

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)

Ma per i personaggi comuni, recodeapparentemente non è necessario. Questo dovrebbe darti caratteri nominati per tutto nel set di caratteri a 128 byte:

printf %b "$(printf \\%04o $(seq 128))" | 
luit -c |
od -A n -t o1z -t a -w12

PRODUZIONE

 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

Naturalmente, sono rappresentati solo 128 byte, ma questo perché il mio locale, charmaps utf-8 o no, usa l' ASCII set di e nient'altro. Quindi è tutto ciò che ottengo. Se lo avessi eseguito senza luitfiltrarlo, l' odavrei riavvolto e avrei stampato di nuovo la stessa mappa\0400.

Tuttavia, ci sono due problemi principali con il metodo sopra. Per prima cosa c'è l'ordine di confronto del sistema: per i locali non ASCII i valori del morso per i set di caratteri non sono semplicemente inseq uence, il che, come penso, è probabilmente il nocciolo del problema che stai cercando di risolvere.

Bene, la tr's manpagina GNU afferma che espanderà il[:upper:] [:lower:] classi in ordine - ma non è molto.

Immagino che potrebbe essere implementata una soluzione pesante sort ma che sarebbe uno strumento piuttosto ingombrante per un'API di programmazione back-end.

recodefarà questa cosa correttamente, ma l'altro giorno non sei sembrato troppo innamorato del programma. Forse le modifiche di oggi getteranno una luce più amichevole o forse no.

GNU offre anche la gettextlibreria di funzioni e sembra essere in grado di risolvere questo problema almeno perLC_MESSAGES contesto:

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

La bind_textdomain_codesetfunzione può essere utilizzata per specificare il set di caratteri di output per i cataloghi di messaggi per il dominio nome dominio . L' argomento del set di codici deve essere un nome di set di codici valido che può essere utilizzato per codici funzione iconv_open o un puntatore null.

Se il parametro codeset è il puntatore null, bind_textdomain_codeset restituisce il set di codici attualmente selezionato per il dominio con il nome domainname . Restituisce NULL se non è stato ancora selezionato alcun set di codici .

La bind_textdomain_codesetfunzione può essere utilizzata più volte. Se utilizzata più volte con lo stesso argomento domainname, la chiamata successiva sovrascrive le impostazioni effettuate dalla precedente.

La bind_textdomain_codesetfunzione restituisce un puntatore a una stringa contenente il nome del set di codici selezionato. La stringa è allocata internamente nella funzione e non deve essere modificata dall'utente. Se il sistema è uscito dal core durante l'esecuzione di bind_textdomain_codeset, il valore restituito è NULL e la variabile globale errno è impostata di conseguenza.

È inoltre possibile utilizzare categorie di caratteri Unicode nativi , che sono indipendenti dalla lingua e rinunciare del tutto alle classi POSIX, o forse chiamare il primo per fornire informazioni sufficienti per definire il secondo.

Oltre alle complicazioni, Unicode offre anche nuove possibilità. Uno è che ogni personaggio Unicode appartiene a una determinata categoria. Puoi abbinare un singolo personaggio appartenente alla categoria "lettera" con \p{L}. Puoi abbinare un singolo personaggio non appartenente a quella categoria con\P{L} .

Ancora una volta, "carattere" significa in realtà "punto di codice Unicode". \p{L}corrisponde a un singolo punto di codice nella categoria "lettera". Se la stringa di input è à codificata come U+0061 U+0300, corrisponde asenza l'accento. Se l'ingresso è àcodificato come U+00E0, corrisponde àall'accento. Il motivo è che entrambi i punti del codice U+0061 (a)e U+00E0 (à)sono nella categoria "lettera", mentreU+0300 è nella categoria "segno".

Ora dovresti capire perché \P{M}\p{M}*+è l'equivalente di \X. \P{M}corrisponde a un punto di codice che non è un segno combinato, mentre \p{M}*+ corrisponde a zero o più punti di codice che combinano segni. Per abbinare una lettera compresi eventuali segni diacritici, utilizzare \p{L}\p{M}*+. Quest'ultima regex corrisponderà sempre à, indipendentemente da come viene codificata. Il quantificatore possessivo si assicura che il backtracking non causi \P{M}\p{M}*+l'abbinamento di un non-mark senza i segni combinati che lo seguono, cosa \X che non farebbe mai.

Lo stesso sito web che ha fornito le informazioni di cui sopra anche discute Tclproprio l' POSIX -compatibile implementazione regex che potrebbe essere un altro modo per raggiungere il tuo obiettivo.

E infine, tra le soluzioni suggerirò che è possibile interrogare il LC_COLLATEfile stesso per la mappa completa e in ordine dei caratteri del sistema. Questo può non sembrare facile, ma dopo averlo compilato localedefcome dimostrato di seguito ho ottenuto un certo successo con quanto segue:

<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

È vero, attualmente, è imperfetto, ma spero che dimostri almeno la possibilità.

A PRIMA VISTA

strings $_/en_GB

#OUTPUT

int_select "<U0030><U0030>"
...
END LC_TELEPHONE

In realtà non sembrava molto, ma poi ho iniziato a notare i copycomandi in tutto l'elenco. Il file sopra sembra copyin "en_US" per esempio, e un altro vero e proprio grande che sembra che tutti condividano in una certa misura è iso_14651_t1_common.

È abbastanza grande:

strings $_ | wc -c

#OUTPUT
431545

Ecco l'intro per /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>;

...

Puoi grepfarlo ovviamente, ma potresti semplicemente:

recode -lf gb

Anziché. Otterresti qualcosa del genere:

Dec  Oct Hex   UCS2  Mne  BS_4730

  0  000  00   0000  NU   null (nul)
  1  001  01   0001  SH   start of heading (soh)
...

... E ALTRO

Esiste anche luitun ptydispositivo di traduzione terminale UTF-8 che suppone che agisca da intermediario per XTerms senza il supporto UTF-8. Gestisce molti switch, come la registrazione di tutti i byte convertiti in un file o -ccome semplice|pipe filtro.

Non mi ero mai reso conto che ci fosse così tanto in questo - i locali, le mappe dei personaggi e tutto il resto. Apparentemente questo è un grosso problema, ma immagino che succeda tutto dietro le quinte. Ce ne sono - almeno sul mio sistema - duecentoman 3 risultati correlati per le ricerche relative alle impostazioni locali.

E c'è anche:

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
...

Andrà avanti per molto tempo.

Le Xlibfunzioni gestiscono tutto il tempo -luit fa parte di quel pacchetto.

Il Tcl_uni... funzioni potrebbero rivelarsi utili.

solo un piccolo <tab>completamento e manricerche e ho imparato molto su questo argomento.

Con localedef- puoi compilare il localesnella tua I18Ndirectory. L'output è funky e non straordinariamente utile - non come charmapsaffatto - ma puoi ottenere il formato raw proprio come hai specificato sopra come ho fatto io:

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

Quindi con odte puoi leggerlo - byte e stringhe:

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...<
...

Anche se è molto lontano dal vincere un concorso di bellezza, questo è un output utilizzabile. Eod è configurabile come vuoi che sia, ovviamente.

Immagino di aver dimenticato anche questi:

    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

Probabilmente me ne sono dimenticato perché non riuscivo a farli funzionare. Non uso mai Perle non so come caricare correttamente un modulo, immagino. Ma le manpagine sembrano piuttosto carine. In ogni caso, qualcosa mi dice che troverai che chiamare un modulo Perl almeno un po 'meno difficile di me. E, ancora una volta, questi erano già sul mio computer - e non uso nemmeno Perl. Ci sono anche alcuni I18Nche ho girato malinconicamente sapendo benissimo che non li avrei nemmeno fatti funzionare.


1
Sono tutte informazioni molto utili e utili, ma che forniscono informazioni sui file di origine (in i18n) che potrebbero essere stati usati o meno per generare la locale che sto attualmente utilizzando. Le informazioni sulla localizzazione probabilmente provengono da /usr/lib/locale/locale-archiveo /some/dir/LC_CTYPE, e questa è la parte rilevante per la mia localizzazione che è memorizzata in quei file che sto cercando.
Stéphane Chazelas,

@StephaneChezales - quindi basta estrarre il tuo LC_STUFFdall'archivio con localedef- lo fa anche quello. Posso anche dimostrarlo. È inoltre possibile visualizzare questo e praticamente tutto il resto, con stringso odo qualsiasi parte del resto. L'ho fatto, comunque. Ma a proposito - charmaps sono le impostazioni locali che stai attualmente utilizzando - e localedefriporteranno anche questo. Questo è anche quello che recodefa.
Mikeserv,

In pratica stai dicendo che possiamo fare a mano ciò che le librerie del sistema fanno per interrogare le informazioni sulla classe di caratteri, ma ciò richiederà migliaia di righe di codice per farlo in modo affidabile e il risultato sarà specifico del sistema. (analizzando l'ambiente allo stesso modo della libreria di sistema (LOCPATH, LANG, LANGUAGE, LC_CTYPE ..., identificare dove cercare i dati, estrarli ...). Non riesco a vedere come estrarre cose dall'archivio con localedef però.
Stéphane Chazelas,

@StephaneChazelas - Io non suggeriscono lo si fa a mano - vi consiglio di farlo con un computer - utilizzando i binari di sistema, come od, recode, uconve tutto il resto. Ma è stato un mio errore - non è localedefquello che lo estrae, è recodequella volontà. Devi dare un'occhiata info recode- e oltre al recodecomando da tavolo che ho mostrato c'è più o meno la stessa cosa - e gestirà le cose nello stesso modo, credo. Non si limita a estrarre il set di caratteri dal nulla. In ogni caso avevo grandi speranze per quei perlmoduli: ne hai provato?
Mikeserv,

1
Se esiste un'API per recuperare l'elenco di caratteri in una determinata classe di caratteri nella locale corrente, è quello che sto cercando. Se riesci a dimostrare come fare, accetterò la risposta. L'unica cosa che mi viene in mente (e come ho ottenuto il "risultato atteso" nella mia domanda) è usare iswblank(3)per tutti i possibili valori dei caratteri.
Stéphane Chazelas,

1

Almeno su sistemi GNU, FreeBSD o Solaris, questo approccio a forza bruta funziona:

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

Mentre per C / POSIX, wchar_t è un tipo opaco che non ha alcuna relazione con Unicode ed è garantito solo per coprire tutti i caratteri supportati dalla locale del sistema, in pratica, nella maggior parte dei sistemi che supportano Unicode, i valori corrispondono ai punti di codice Unicode e le definizioni delle impostazioni locali sono esse stesse basate su Unicode.

Unicode è pensato per essere un superset di tutti i set di caratteri noti, quindi il ciclo su tutti i punti di codice validi in Unicode (da 0 a 0xD7FF e da 0xE000 a 0x10FFFF) dovrebbe elencare almeno tutti i caratteri supportati da un determinato set di caratteri.

Qui, stiamo usando l'API standard delle impostazioni locali del sistema per verificare quali sono di un determinato tipo e per convertirli nella loro forma codificata nella codifica delle impostazioni locali. Noi usiamoperl e il suocharnames modulo solo per ottenere il nome da un determinato punto di codice Unicode.

In locali che utilizzano codifiche con stato come ISO-2022-JP, ci assicuriamo che il modulo codificato sia visualizzato da uno stato iniziale predefinito.

Non ho trovato un sistema che avesse installato impostazioni locali con una codifica dei caratteri con stato ma almeno sui sistemi GNU, è possibile generarne alcune in modo da poter creare una locale non autorizzata (e almeno gli strumenti GNU non funzionano correttamente in quelli locali). Ad esempio, con un'impostazione internazionale personalizzata che utilizza ISO-2022-JP con un'impostazione ja_JPinternazionale normale , ottengo:

$ 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

Confrontare con:

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

In ISO-2022-JP, la 1B 24 42sequenza ( \e$B) passa da ASCII a uno stato in cui i caratteri sono espressi come 2 (7 bit) byte (qui 21 21 per quello SPAZIO IDEOGRAFICO). Mentre in EUCJP, sono gli stessi byte, ma il cambio di stato viene eseguito capovolgendo l'ottavo bit ( A1 = 21 | 0x80) che lo rende più stateless.

Ciò significa che in quelle codifiche stateful, ci sono diversi modi per scrivere un dato carattere (ad esempio inserendo molti di quelli cambi di stato sequenze di ), e la sequenza mostrata da quel codice sopra è solo una di esse (quella canonica da un'iniziale stato predefinito).

Mentre per un locale normale, caratteri non possono essere fuori 0..0xD7FF, 0xE000..0x10FFFF per un ladro locale, qualsiasi carattere nell'intervallo supportato da wchar_t può essere. Ad esempio, potrei creare un locale in cui i caratteri U + DCBA o U + 12345678 (o sarebbero caratteri se fossero autorizzati) sono spazi vuoti . Ecco perché vorresti compilare quel codice con-D SUPPORT_ROGUE_LOCALES per coprirli, anche se ciò significa che ci vuole molto più tempo per scansionare l'intero elenco.

Non ho potuto usare la soluzione di @ mikeserv poiché recodeusa le proprie conversioni, non è più mantenuta e supporta solo caratteri Unicode fino a 0xFFFF e GNU tralmeno non funziona con caratteri multi-byte.

Non ho potuto usare @ ChrisDown perché pythonnon ha interfacce per le classi di caratteri POSIX.

Ho provato Perl, ma è falso per punti di codice tra 128 e 255 per locali a più byte diversi da UTF-8 e non utilizza le librerie di conversione del sistema.


Penso che questo sia effettivamente l'unico modo per farlo, ma soffre di diversi problemi, a partire dal fatto che hai usato le conoscenze precedenti per decidere sulla gamma di codici legali. Almeno in teoria, se si utilizza una charmap Unicode, le classi di caratteri sono indipendenti dallo script (secondo lo standard Unicode, non le versioni locali C), ma le "categorie generali" Unicode non sono uguali alle classi di caratteri C. A proposito, i tipi i18n di glibc includono altre due classi di personaggi: combininge combining_level3(vale a dire iswctype(i, wctype("combining")))
rici

@rici, vedi modifica (e anche della domanda).
Stéphane Chazelas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.