Commande pour récupérer la liste des caractères d'une classe de caractères donnée dans les paramètres régionaux actuels

18

Ce qui pourrait être un moyen de récupérer une liste de tous les caractères d'une classe de caractères donnée (comme blank, alpha, digit...) dans la configuration locale.

Par exemple,

LC_ALL=en_GB.UTF-8 that-command blank

idéalement, sur mon système Debian, afficherait quelque chose comme:

      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

Et dans les paramètres régionaux C pourrait afficher quelque chose comme:

09 U+0009 HORIZONTAL TAB
20 U+0020 SPACE

Autrement dit, la représentation du caractère dans les paramètres régionaux en termes de tableaux d'octets (comme UTF-8 dans le premier exemple et octet unique dans le second), le point de code de caractère Unicode équivalent et une description.

Le contexte

(modifier) ​​Maintenant que la vulnérabilité a été corrigée et divulguée depuis longtemps, je peux ajouter un peu de contexte.

J'ai posé cette question au moment où j'enquêtais CVE 2014-0475 . glibcavait un bug en ce qu'il permettait à l'utilisateur d'utiliser des paramètres régionaux comme LC_ALL=../../../../tmp/evil-localeceux-ci sont résolus par rapport au chemin de recherche standard des paramètres régionaux du système et permettait ainsi d'utiliser n'importe quel fichier comme définition de paramètres régionaux.

Je pourrais créer un environnement local voyous par exemple avec un seul octet par jeu de caractères où la plupart des caractères sauf s, het quelques autres étaient considérés comme des blancs et qui seraient bashexécutés shlors de l'analyse d'un /etc/bash.bashrcfichier Debian typique (et qui pourrait être utilisé pour obtenir un accès shell sur un gitle serveur d'hébergement par exemple fourni bashest utilisé comme shell de connexion de l' gitutilisateur du serveur et que le sshserveur accepte LC_*/ LANGvariables et que l'attaquant peut télécharger des fichiers sur le serveur).

Maintenant, si jamais je trouvais une LC_CTYPE(définition locale compilée) dans /tmp/evil, comment pourrais-je savoir que c'était une voyou et de quelle manière.

Mon objectif est donc de décompiler ces définitions de paramètres régionaux et, dans le cas contraire, de savoir au moins quel caractère (ainsi que leur codage) se trouvent dans une classe de caractères donnée.

Donc, avec cela à l'esprit:

  • Les solutions qui regardent les fichiers source pour les paramètres régionaux (les définitions de paramètres régionaux comme celles de /usr/share/i18n/localeDebian) ne sont d'aucune utilité dans mon cas.
  • Les propriétés des caractères Unicode ne sont pas pertinentes. Je me soucie seulement de ce que dit la locale. Sur un système Debian, même entre deux locales du système UTF-8, et encore moins des locales escrocs, la liste des caractères d'une classe peut être différente.
  • Des outils comme recode, pythonou perlqui effectuent la conversion d'octet / multi-octet vers / à partir de caractères ne peuvent pas être utilisés car ils peuvent (et en pratique le font) effectuer la conversion d'une manière différente de la locale.
Stéphane Chazelas
la source
Pour la plupart des paramètres régionaux, cela vient en fin de compte du contenu LC_CTYPE dans (avec glibc) /usr/share/i18n/locales/i18n... qui bien sûr provient en grande partie de la base de données de caractères Unicode. Bien sûr, ce serait bien d'avoir une commande
derobert
@derobert, oui, alors que locale(au moins celui de GNU) récupère la plupart des informations stockées dans de nombreuses catégories, les choses ne sont pas les plus importantes dans LC_CTYPE et LC_COLLATE. Je me demande s'il y a une API cachée pour récupérer ces informations ou décompiler les informations locales.
Stéphane Chazelas
Ouais - vous pouvez obtenir cette information analysée - Je viens enfin de terminer mon montage. Il y a plusieurs commandes que vous avez probablement déjà installées - du moins je l'ai fait, et je ne les connaissais même pas. J'espère que ça aide. Plus précisément recodeet uconvpeut vous donner ce que vous dites que vous recherchez. Peut-être même juste luitet odje suppose ...
mikeserv
C'est très bien! Cela signifie que vous n'avez pas besoin perldu tout, je pense.
mikeserv
Je semble être en mesure d'extraire essentiellement mon jeu de caractères LC_CTYPEavec od -A n -t c <LC_CTYPE | tsortprobablement que vous l'avez déjà essayé, mais je n'en avais jamais entendu parler auparavant et je lisais infoet cela m'a rappelé cela - et cela semble fonctionner. Il y en a aussi ptxmais je pense que c'est moins pertinent. Quoi qu'il en soit, si vous ne l'avez pas essayé et décidez de le faire - avertissement juste - cela nécessite un peu de patience. lehman.cuny.edu/cgi-bin/man-cgi?tsort+1
mikeserv

Réponses:

7

SOLUTION FINALE POSSIBLE

J'ai donc pris toutes les informations ci-dessous et trouvé ceci:

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

REMARQUE :

J'utilise odcomme filtre final ci-dessus de préférence et parce que je sais que je ne travaillerai pas avec des caractères multi-octets, qu'il ne gérera pas correctement. recode u2..dumpva à la fois générer une sortie plus semblable à celle spécifiée dans la question et gérer correctement les caractères larges.

PRODUCTION

        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 DU PROGRAMMATEUR

Comme je le démontre ci-dessous, recodevous fournira votre carte de personnage complète. Selon son manuel, il le fait d'abord en fonction de la valeur actuelle de la DEFAULT_CHARSETvariable d'environnement, ou, à défaut, il fonctionne exactement comme vous le spécifiez:

Lorsqu'un nom de jeu de caractères est omis ou laissé vide, la valeur de la DEFAULT_CHARSETvariable dans l'environnement est utilisée à la place. Si cette variable n'est pas définie, la recodebibliothèque utilise l' encodage des paramètres régionaux en cours. Sur les systèmes compatibles POSIX , cela dépend de la première valeur non vide parmi les variables d'environnement LC_ALL, LC_CTYPE, LANGet peut être déterminée via la commandelocale charmap.

Il convient également de noter recodequ'il s'agit d'une API :

Le programme nommé recoden'est qu'une application de sa bibliothèque de recodage. La bibliothèque de recodage est disponible séparément pour les autres programmes C. Un bon moyen d'acquérir une certaine familiarité avec la bibliothèque de recodage est de se familiariser avec le recodeprogramme lui-même.

Pour utiliser la bibliothèque de recodage une fois qu'elle est installée, un programme C doit avoir une ligne:

#include <recode.h>

Pour une comparaison de chaînes conviviale à l'échelle internationale Les normes POSIXet Cdéfinissent la strcoll()fonction:

La strcoll()fonction doit comparer la chaîne pointée par s1la chaîne pointée par s2, toutes deux interprétées comme appropriées à la catégorie LC_COLLATE des paramètres régionaux actuels.

La strcoll()fonction ne doit pas modifier le paramètre errno en cas de succès.

Étant donné qu'aucune valeur de retour n'est réservée pour indiquer une erreur, une application souhaitant rechercher des situations d'erreur doit définir errno sur 0, puis appeler strcoll(), puis vérifier errno.

Voici un exemple distinct de son utilisation:

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

En ce qui concerne les POSIXclasses de personnages, vous avez déjà noté que vous avez utilisé l' CAPI pour les trouver. Pour les caractères et les classes Unicode, vous pouvez utiliser le jeu de caractères recode's dump-with-names pour obtenir la sortie souhaitée. De son manuel à nouveau :

Par exemple, la commande recode l2..full < inputimplique une conversion nécessaire de Latin-2 à UCS-2, car le vidage avec des noms est uniquement connecté à partir de UCS-2. Dans de tels cas, recoden'affiche pas les codes Latin-2 d'origine dans le vidage, uniquement les valeurs UCS-2 correspondantes . Pour donner un exemple plus simple, la commande

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

produit la sortie suivante:

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)

Le commentaire descriptif est donné en anglais et en ASCII, mais si la description en anglais n'est pas disponible mais en français, la description en français est donnée à la place, en utilisant le latin-1. Cependant, si la variable LANGUAGEou l' LANGenvironnement commence par les lettres fr , la préférence de listage va au français lorsque les deux descriptions sont disponibles.

En utilisant une syntaxe similaire à celle ci-dessus combinée avec son jeu de données de test inclus, je peux obtenir ma propre carte de caractères avec:

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

PRODUCTION

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)

Mais pour les personnages communs, recoden'est apparemment pas nécessaire. Cela devrait vous donner des caractères nommés pour tout dans un jeu de caractères de 128 octets:

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

PRODUCTION

 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

Bien sûr, seuls 128 octets sont représentés, mais c'est parce que mes paramètres régionaux, utf-8 charmaps ou non, utilisent le jeu de caractères ASCII et rien de plus. C'est tout ce que je reçois. Si je l'exécutais sans le luitfiltrer, odje le retournerais et imprimerais à nouveau la même carte jusqu'à\0400.

Il existe cependant deux problèmes majeurs avec la méthode ci-dessus. Il y a d'abord l'ordre de classement du système - pour les paramètres régionaux non ASCII, les valeurs de morsure pour les jeux de caractères ne sont pas simplement in sequence, ce qui, comme je pense, est probablement au cœur du problème que vous essayez de résoudre.

Eh bien, la tr's manpage GNU indique qu'elle étendra les [:upper:] [:lower:]classes dans l'ordre - mais ce n'est pas beaucoup.

J'imagine qu'une solution lourde pourrait être implémentée avec sortmais ce serait un outil plutôt lourd pour une API de programmation backend.

recodefera cette chose correctement, mais vous ne sembliez pas trop amoureux du programme l'autre jour. Peut-être que les modifications d'aujourd'hui apporteront une lumière plus amicale ou non.

GNU propose également la gettextbibliothèque de fonctions, et il semble pouvoir résoudre ce problème au moins pour le LC_MESSAGEScontexte:

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

La bind_textdomain_codesetfonction peut être utilisée pour spécifier le jeu de caractères de sortie pour les catalogues de messages pour le domaine nom_domaine . L' argument de jeu de codes doit être un nom de jeu de codes valide qui peut être utilisé pour la fonction iconv_open ou un pointeur nul.

Si le jeu de codes paramètre est le pointeur NULL, bind_textdomain_codeset retourne actuellement sélectionné codeset pour le domaine avec le nom nomdomaine . Il renvoie NULL si aucun jeu de codes n'a encore été sélectionné.

La bind_textdomain_codesetfonction peut être utilisée plusieurs fois. S'il est utilisé plusieurs fois avec le même argument de nom de domaine, l'appel ultérieur remplace les paramètres définis par le précédent.

La bind_textdomain_codesetfonction renvoie un pointeur sur une chaîne contenant le nom du jeu de codes sélectionné. La chaîne est allouée en interne dans la fonction et ne doit pas être modifiée par l'utilisateur. Si le système est sorti du cœur pendant l'exécution de bind_textdomain_codeset, la valeur de retour est NULL et la variable globale errno est définie en conséquence.

Vous pouvez également utiliser des catégories de caractères Unicode natives , qui sont indépendantes de la langue et renoncer complètement aux classes POSIX, ou peut-être faire appel aux premières pour vous fournir suffisamment d'informations pour définir les dernières.

En plus des complications, Unicode apporte également de nouvelles possibilités. La première est que chaque caractère Unicode appartient à une certaine catégorie. Vous pouvez faire correspondre un seul caractère appartenant à la catégorie "lettre" avec \p{L}. Vous pouvez faire correspondre un seul caractère n'appartenant pas à cette catégorie avec \P{L}.

Encore une fois, "caractère" signifie vraiment "point de code Unicode". \p{L}correspond à un point de code unique dans la catégorie "lettre". Si votre chaîne d'entrée est à codée en tant que U+0061 U+0300, elle correspond asans l'accent. Si l'entrée est àcodée en tant que U+00E0, elle correspond àà l'accent. La raison en est que les deux points de code U+0061 (a)et U+00E0 (à)sont dans la catégorie "lettre", tandis que U+0300dans la catégorie "marque".

Vous devez maintenant comprendre pourquoi \P{M}\p{M}*+est l'équivalent de \X. \P{M}correspond à un point de code qui n'est pas une marque de combinaison, tandis que \p{M}*+ correspond à zéro ou plusieurs points de code qui combinent des marques. Pour faire correspondre une lettre incluant des signes diacritiques, utilisez \p{L}\p{M}*+. Cette dernière expression régulière correspondra toujours à, quelle que soit la façon dont elle est codée. Le quantificateur possessif s'assure que le retour arrière ne fait pas \P{M}\p{M}*+correspondre à une non-marque sans les marques de combinaison qui le suivent, ce \X qui ne le ferait jamais.

Le même site Web qui a fourni les informations ci - dessus discute aussi Tclpropre d » Posix compatibles avec la norme mise en œuvre de regex qui pourrait être encore une autre façon d'atteindre votre objectif.

Enfin, parmi les solutions, je proposerai que vous puissiez interroger le LC_COLLATEfichier lui-même pour la table de caractères système complète et en ordre . Cela peut ne pas sembler facile à faire, mais j'ai obtenu un certain succès avec ce qui suit après l'avoir compilé localedefcomme illustré ci-dessous:

<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

Il est, certes, actuellement imparfait, mais j'espère que cela démontre au moins la possibilité.

AU PREMIER BLUSH

strings $_/en_GB

#OUTPUT

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

Cela ne ressemblait vraiment pas à beaucoup, mais j'ai commencé à remarquer des copycommandes dans la liste. Le fichier ci-dessus semble copydans "en_US" par exemple, et un autre très gros qu'il semble qu'ils partagent tous dans une certaine mesure est iso_14651_t1_common.

C'est assez gros:

strings $_ | wc -c

#OUTPUT
431545

Voici l'intro de /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>;

...

Vous pouvez le faire grepbien sûr, mais vous pourriez simplement:

recode -lf gb

Au lieu. Vous obtiendriez quelque chose comme ceci:

Dec  Oct Hex   UCS2  Mne  BS_4730

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

... ET PLUS

Il existe également un luitterminal de ptytraduction UTF-8 , je suppose, qui sert d'intermédiaire pour les XTerms sans prise en charge UTF-8. Il gère de nombreux commutateurs, tels que la consignation de tous les octets convertis dans un fichier ou -ccomme un simple |pipefiltre.

Je n'ai jamais réalisé qu'il y avait tant de choses à cela - les paramètres régionaux et les cartes de personnages et tout cela. C'est apparemment un gros problème mais je suppose que tout se passe dans les coulisses. Il existe - au moins sur mon système - quelques centaines de man 3résultats liés aux recherches liées aux paramètres régionaux.

Et il y a aussi:

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

Cela durera très longtemps.

Les Xlibfonctions gèrent cela tout le temps - font luitpartie de ce package.

Les Tcl_uni...fonctions pourraient également s'avérer utiles.

juste un peu d' <tab>achèvement et de manrecherches et j'ai beaucoup appris sur ce sujet.

Avec localedef- vous pouvez compiler le localesdans votre I18Nrépertoire. La sortie est géniale et pas extraordinairement utile - pas du charmapstout - mais vous pouvez obtenir le format brut comme vous l'avez spécifié ci-dessus comme je l'ai fait:

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

Ensuite, avec odvous pouvez le lire - octets et chaînes:

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

Bien qu'il soit loin de gagner un concours de beauté, c'est une sortie utilisable. Et odest aussi configurable que vous le souhaitez, bien sûr.

Je suppose que j'ai également oublié ces derniers:

    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

Je les ai probablement oubliés parce que je ne pouvais pas les faire travailler. Je n'utilise jamais Perlet je ne sais pas comment charger un module correctement je suppose. Mais les manpages sont plutôt jolies. En tout cas, quelque chose me dit que vous trouverez qu'il est au moins un peu moins difficile d'appeler un module Perl que moi. Et, encore une fois, ils étaient déjà sur mon ordinateur - et je n'utilise même jamais Perl. Il y a aussi notamment quelques I18N- uns que j'ai fait avec mélancolie en sachant très bien que je ne les ferais pas travailler non plus.

mikeserv
la source
1
Ce sont toutes des informations très intéressantes et utiles, mais qui donnent des informations sur les fichiers source (en i18n) qui peuvent ou non avoir été utilisés pour générer les paramètres régionaux que j'utilise actuellement. Les informations sur les paramètres régionaux proviennent probablement de /usr/lib/locale/locale-archiveou /some/dir/LC_CTYPE, et c'est la partie pertinente à mes paramètres régionaux qui est stockée dans les fichiers que je recherche.
Stéphane Chazelas
@StephaneChezales - il suffit donc d'extraire votre LC_STUFFde l'archive avec localedef- il le fait aussi. Je peux aussi faire une démonstration, je suppose. Vous pouvez également voir cela et à peu près tout le reste avec stringsou odou tout le reste. Je l'ai fait de toute façon. Mais au fait - ce charmaps sont les paramètres régionaux que vous utilisez actuellement - et en localedefferont également rapport. C'est aussi ce qui recodefait aussi.
mikeserv
Vous dites essentiellement que nous pouvons faire à la main ce que les bibliothèques du système font pour interroger les informations de classe de caractères, mais cela va nécessiter des milliers de lignes de code pour le faire de manière fiable et le résultat sera spécifique au système. (analyser l'environnement de la même manière que la bibliothèque système (LOCPATH, LANG, LANGUAGE, LC_CTYPE ..., identifier où chercher les données, les extraire ...). Je ne vois pas comment extraire des éléments de l'archive avec localedef cependant.
Stéphane Chazelas
@StephaneChazelas - Je ne suggère pas que vous le faites à la main - je vous suggère de le faire avec un ordinateur - en utilisant les binaires du système tels que od, recode, uconvet le reste. Mais c'était mon erreur - ce n'est pas localedefcela qui l'extrait, c'est recodecette volonté. Vous devez vérifier info recode- et en plus de la recodecommande de table que je montre, il y a à peu près la même chose - et cela traitera les choses de la même manière, je pense. Il ne fait pas que tirer votre charset de l'air. En tout cas, j'avais de grands espoirs pour ces perlmodules - en avez-vous essayé?
mikeserv
1
S'il existe une API pour récupérer la liste des caractères d'une classe de caractères donnée dans les paramètres régionaux actuels, c'est précisément ce que je recherche. Si vous pouvez montrer comment procéder, j'accepterai la réponse. La seule chose à laquelle je pouvais penser (et comment j'ai obtenu la "sortie attendue" dans ma question) est d'utiliser iswblank(3)toutes les valeurs de caractères possibles.
Stéphane Chazelas
1

Sur les systèmes GNU, FreeBSD ou Solaris au moins, cette approche par force brute fonctionne:

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

Alors que par C / POSIX, wchar_test un type opaque qui n'a aucune relation avec Unicode et est uniquement garanti pour couvrir tous les caractères pris en charge par les paramètres régionaux du système, dans la pratique, dans la plupart des systèmes qui prennent en charge Unicode, les valeurs correspondent aux points de code Unicode et les définitions de paramètres régionaux sont elles-mêmes basées sur Unicode.

Unicode est censé être un sur-ensemble de tous les jeux de caractères connus, donc boucler sur tous les points de code valides en Unicode (0 à 0xD7FF et 0xE000 à 0x10FFFF) devrait répertorier au moins tous les caractères pris en charge par un jeu de caractères donné.

Ici, nous utilisons l'API standard locale du système pour vérifier ceux qui sont d'un type donné et pour les convertir dans leur forme encodée dans l'encodage des paramètres régionaux. Nous utilisons perlet son charnamesmodule uniquement pour obtenir le nom d'un point de code Unicode donné.

Sur les paramètres régionaux qui utilisent des codages avec état comme ISO-2022-JP, nous nous assurons que la forme codée est affichée à partir d'un état initial par défaut.

Je n'ai pas trouvé de système qui avait installé des paramètres régionaux avec un codage de caractères avec état, mais au moins sur les systèmes GNU, il est possible d'en générer pour que des paramètres régionaux malveillants puissent être créés (et au moins les outils GNU ne fonctionnent pas correctement dans ces locales). Par exemple, avec un environnement local personnalisé qui utilise ISO-2022-JP avec un ja_JPenvironnement local normal , j'obtiens:

$ 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

Comparer avec:

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

Dans ISO-2022-JP, la 1B 24 42séquence ( \e$B) passe de ASCII à un état où les caractères sont exprimés en 2 octets (7 bits) (ici 21 21 pour cet ESPACE IDÉOGRAPHIQUE). En EUCJP, ce sont les mêmes octets, mais la commutation d'état se fait en inversant le 8ème bit ( A1 = 21 | 0x80), ce qui le rend plus sans état.

Cela signifie que dans ces encodages avec état, il existe plusieurs façons d'écrire un caractère donné (par exemple en insérant plusieurs de ces séquences de commutation d'état ), et la séquence illustrée par ce code ci-dessus n'est qu'une d'entre elles (la canonique à partir d'une initiale État par défaut).

Alors que pour un environnement local normal, les caractères ne peuvent pas être en dehors de 0..0xD7FF, 0xE000..0x10FFFF, pour un environnement local voyous , n'importe quel caractère de la plage prise en charge par wchar_t peut l'être. Par exemple, je pourrais créer un environnement local où les caractères U + DCBA ou U + 12345678 (ou seraient des caractères s'ils étaient autorisés) sont vides . C'est pourquoi vous voudriez compiler ce code avec -D SUPPORT_ROGUE_LOCALESpour les couvrir, bien que cela signifie que cela prend beaucoup plus de temps pour analyser toute la liste.

Je ne pouvais pas utiliser la solution de @ mikeserv car elle recodeutilise ses propres conversions, n'est plus maintenue et ne prend en charge que les caractères Unicode jusqu'à 0xFFFF, et GNU trau moins ne fonctionne pas avec les caractères multi-octets.

Je ne pouvais pas utiliser @ ChrisDown car pythonn'a pas d'interfaces avec les classes de caractères POSIX.

J'ai essayé Perl, mais c'est faux pour les points de code entre 128 et 255 pour les locales multi-octets autres que UTF-8 et n'utilise pas les bibliothèques de conversion du système.

Stéphane Chazelas
la source
Je pense que c'est effectivement la seule façon de le faire, mais cela souffre de plusieurs problèmes, à commencer par le fait que vous avez utilisé des connaissances préalables pour décider de la gamme de points de code légaux. En théorie du moins, si vous utilisez un charmap Unicode, les classes de caractères sont indépendantes du script (selon la norme Unicode, pas les locales C), mais les "catégories générales" Unicode ne sont pas les mêmes que les classes de caractères C. BTW, les ctypes i18n de glibc incluent deux autres classes de caractères: combininget combining_level3(à savoir iswctype(i, wctype("combining")))
rici
@rici, voir edit (et aussi de la question).
Stéphane Chazelas