Befehl zum Abrufen der Liste der Zeichen in einer bestimmten Zeichenklasse im aktuellen Gebietsschema

18

Was könnte ein Weg sein , eine Liste aller Zeichen in einem bestimmten Zeichenklasse abzurufen (wie blank, alpha, digit...) in der aktuellen Locale.

Zum Beispiel,

LC_ALL=en_GB.UTF-8 that-command blank

Im Idealfall würde auf meinem Debian-System Folgendes angezeigt:

      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

Und im C-Gebietsschema könnte so etwas angezeigt werden:

09 U+0009 HORIZONTAL TAB
20 U+0020 SPACE

Das heißt, die Darstellung des Zeichens im Gebietsschema in Form von Arrays von Bytes (wie UTF-8 im ersten Beispiel und Einzelbyte im zweiten), dem entsprechenden Unicode-Zeichen-Codepunkt und einer Beschreibung.

Kontext

(edit) Nachdem die Sicherheitsanfälligkeit lange behoben und aufgedeckt wurde, kann ich ein wenig Kontext hinzufügen.

Ich habe diese Frage gestellt, als ich CVE 2014-0475 untersuchte . glibchatte den Fehler, dass der Benutzer solche Gebietsschemas verwenden konnte LC_ALL=../../../../tmp/evil-locale, die relativ zum standardmäßigen Suchpfad für das Gebietsschema des Systems aufgelöst wurden, und daher jede Datei als Gebietsschemadefinition verwenden konnte.

Ich könnte einen Schelm locale erstellen zum Beispiel mit einem Byte pro Zeichen charset , wo die meisten Zeichen außer s, hund ein paar andere wurden als Leerstellen und das würde bashlaufen , shwährend eine typische Debian - Parsing - /etc/bash.bashrcDatei (und das verwendet werden könnte , Shell - Zugriff auf einem bekommen gitDer zum Beispiel bereitgestellte Hosting-Server bashwird als Anmeldeshell des gitServerbenutzers verwendet, und der sshServer akzeptiert LC_*/ LANGVariablen und der Angreifer kann Dateien auf den Server hochladen.

Wenn ich jemals eine LC_CTYPE(kompilierte Gebietsschemadefinition) in gefunden hätte /tmp/evil, wie würde ich dann herausfinden, dass es eine Schurken- Definition war und auf welche Weise.

Mein Ziel ist es daher, diese Gebietsschemadefinitionen zu dekompilieren und, falls nicht, zumindest zu wissen, welche Zeichen (zusammen mit ihrer Codierung) in einer bestimmten Zeichenklasse enthalten sind.

In diesem Sinne:

  • Lösungen, die sich die Quelldateien für das Gebietsschema ansehen (die Gebietsschemadefinitionen wie die in /usr/share/i18n/localeDebian), sind in meinem Fall nicht von Nutzen.
  • Unicode-Zeicheneigenschaften sind irrelevant. Mir ist nur wichtig, was das Gebietsschema sagt. Auf einem Debian-System kann die Liste der Zeichen in einer Klasse sogar zwischen zwei UTF-8-System-Gebietsschemata unterschiedlich sein, geschweige denn zwischen falschen.
  • Tools wie recode, pythonoder perldas tun , um die Byte / Multi-Byte zu / von Zeichenkonvertierung nicht verwendet werden können , wie sie können (und in der Praxis tun) , um die Umwandlung in einer anderen Art und Weise machen als die locale.
Stéphane Chazelas
quelle
Für die meisten Gebietsschemata kommt es letztendlich von den LC_CTYPE-Inhalten (mit glibc) /usr/share/i18n/locales/i18n... die natürlich größtenteils aus der Unicode- Zeichendatenbank stammen. Natürlich wäre es schön, ein Kommando zu haben
derobert
@derobert, ja, während locale(zumindest die GNU- Version ) viele der in vielen Kategorien gespeicherten Informationen abruft, sind dies nicht die wichtigsten in LC_CTYPE und LC_COLLATE. Ich frage mich, ob es eine versteckte API gibt, um diese Informationen abzurufen oder die Gebietsschemainformationen zu dekompilieren.
Stéphane Chazelas
Ja - Sie können diese Informationen analysieren lassen - ich bin gerade erst dazu gekommen, meine Bearbeitung abzuschließen. Es gibt einige Befehle, die Sie wahrscheinlich bereits installiert haben - zumindest habe ich sie installiert, und ich wusste nicht einmal davon. Ich hoffe, es hilft. Speziell recodeund uconvkann Ihnen geben, was Sie sagen, was Sie suchen. Möglicherweise sogar nur luitund odich denke ...
mikeserv
Das ist sehr gut! Das heißt, Sie brauchen perlüberhaupt nicht, denke ich.
mikeserv
Ich scheine im Grunde genommen in der Lage zu sein, meinen Zeichensatz LC_CTYPEmit zu extrahieren. od -A n -t c <LC_CTYPE | tsortWahrscheinlich haben Sie ihn bereits ausprobiert, aber ich hatte noch nie zuvor davon gehört, und ich habe durchgelesen infound es hat mich daran erinnert - und es scheint zu funktionieren. Es gibt auch, ptxaber ich denke, es ist weniger relevant. Wie auch immer, wenn Sie es noch nicht ausprobiert haben und sich dazu entschließen - eine faire Warnung -, erfordert es ein wenig Geduld. lehman.cuny.edu/cgi-bin/man-cgi?tsort+1
mikeserv

Antworten:

7

MÖGLICHE LÖSUNG

Daher habe ich die folgenden Informationen zusammengestellt:

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

HINWEIS :

Ich benutze odals letzten Filter oben und weil ich weiß, dass ich nicht mit Multi-Byte-Zeichen arbeiten werde, die es nicht richtig handhaben wird. recode u2..dumpBeide erzeugen eine Ausgabe, die der in der Frage angegebenen ähnelt, und verarbeiten breite Zeichen korrekt.

AUSGABE

        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

PROGRAMMER'S API

Wie ich unten demonstriere, recodebekommst du deine komplette Charakterkarte. Entsprechend dem Handbuch wird dies zuerst anhand des aktuellen Werts der DEFAULT_CHARSETUmgebungsvariablen ausgeführt. Andernfalls wird genau so vorgegangen, wie Sie es angegeben haben:

Wenn ein Zeichensatzname weggelassen oder leer gelassen DEFAULT_CHARSETwird, wird stattdessen der Wert der Variablen in der Umgebung verwendet. Wenn diese Variable nicht definiert ist, verwendet die recodeBibliothek die Codierung des aktuellen Gebietsschemas. Bei POSIX- kompatiblen Systemen hängt dies vom ersten nicht leeren Wert unter den Umgebungsvariablen ab LC_ALL, LC_CTYPE, LANGund kann über den Befehl ermittelt werdenlocale charmap.

Erwähnenswert recodeist auch, dass es sich um eine API handelt :

Das genannte Programm recodeist nur eine Anwendung seiner Rekodierungsbibliothek. Die Rekodierungsbibliothek ist für andere C-Programme separat erhältlich. Eine gute Möglichkeit, sich mit der Neukodierungsbibliothek vertraut zu machen, besteht darin, sich mit dem recodeProgramm selbst vertraut zu machen .

Um die nach der Installation installierte Rekodierungsbibliothek zu verwenden, muss ein C-Programm eine Zeile haben:

#include <recode.h>

Für einen international freundlichen Stringvergleich definieren Die POSIXund CStandards die strcoll()Funktion:

Die strcoll()Funktion vergleicht die Zeichenfolge, auf die von verwiesen wird, mit s1der Zeichenfolge, auf die von verwiesen wird s2. Beide werden entsprechend der Kategorie LC_COLLATE des aktuellen Gebietsschemas interpretiert.

Die strcoll()Funktion soll bei Erfolg die Einstellung von errno nicht ändern.

Da kein Rückgabewert reserviert ist, um einen Fehler anzuzeigen, sollte eine Anwendung, die nach Fehlersituationen suchen möchte, errno auf 0 setzen, dann aufrufen strcoll()und dann errno überprüfen.

Hier ist ein separat platziertes Beispiel für die Verwendung:

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

In Bezug auf die POSIXZeichenklassen haben Sie bereits festgestellt, dass Sie die CAPI verwendet haben, um diese zu finden. Für Unicode-Zeichen und -Klassen können Sie den Zeichensatz recode's dump-with-names verwenden , um die gewünschte Ausgabe zu erhalten. Nochmals aus dem Handbuch :

Beispielsweise recode l2..full < inputimpliziert der Befehl eine notwendige Konvertierung von Latin-2 nach UCS-2, da dump-with-names nur von UCS-2 aus verbunden wird. In solchen Fällen werden im Dump recodenicht die ursprünglichen Latin-2- Codes angezeigt , sondern nur die entsprechenden UCS-2- Werte. Um ein einfaches Beispiel zu geben, der Befehl

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

erzeugt die folgende Ausgabe:

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)

Der beschreibende Kommentar ist in Englisch und ASCII angegeben. Wenn jedoch keine englische, sondern eine französische Beschreibung verfügbar ist, wird stattdessen die französische Beschreibung mit Latin-1 angegeben. Wenn jedoch die Umgebungsvariable LANGUAGEoder LANGmit den Buchstaben fr beginnt , wird die Listeneinstellung auf Französisch gesetzt, wenn beide Beschreibungen verfügbar sind.

Wenn ich eine ähnliche Syntax wie oben in Kombination mit dem enthaltenen Testdatensatz verwende, kann ich meine eigene Zeichentabelle erstellen mit:

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

AUSGABE

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)

Aber für gewöhnliche Charaktere recodeist das anscheinend nicht nötig. Dies sollte Ihnen benannte Zeichen für alles im 128-Byte-Zeichensatz geben:

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

AUSGABE

 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

Natürlich werden nur 128 Bytes dargestellt, aber das liegt daran, dass mein Gebietsschema, utf-8 charmaps oder nicht, den ASCII- Zeichensatz verwendet und sonst nichts. Das ist alles was ich bekomme. Wenn ich es luitlaufen lassen odwürde, ohne es zu filtern, würde ich es zurückrollen und die gleiche Karte erneut drucken, bis\0400.

Es gibt jedoch zwei Hauptprobleme bei der obigen Methode. Erstens gibt es die Sortierreihenfolge des Systems - für Nicht-ASCII-Gebietsschemata sind die Bite-Werte für die Zeichensätze nicht einfach von seqBedeutung, was, wie ich denke, der Kern des Problems ist, das Sie zu lösen versuchen.

Nun, auf der GNU- tr's manSeite heißt es, dass die [:upper:] [:lower:]Klassen der Reihe nach erweitert werden - aber das ist nicht viel.

Ich stelle mir vor sort, dass eine schwierige Lösung implementiert werden könnte, aber das wäre ein ziemlich unhandliches Werkzeug für eine Backend-Programmierschnittstelle.

recodeIch werde das richtig machen, aber Sie schienen neulich nicht allzu verliebt in das Programm zu sein. Vielleicht werden die heutigen Änderungen ein freundlicheres Licht darauf werfen oder vielleicht auch nicht.

GNU bietet auch die gettextFunktionsbibliothek an, und es scheint in der Lage zu sein , dieses Problem zumindest für den LC_MESSAGESKontext anzugehen :

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

Die bind_textdomain_codesetFunktion kann verwendet werden , um das Ausgangszeichensatz für die Nachrichtenkataloge für Domäne angeben domänen . Das Argument codeset muss ein gültiger Codename sein, der für die Funktion iconv_open verwendet werden kann, oder ein Nullzeiger.

Wenn der Codeset- Parameter der Nullzeiger ist, wird bind_textdomain_codeset der aktuell ausgewählte Codeset für die Domäne mit dem Namen Domänenname zurückgegeben . Es wird NULL zurückgegeben, wenn noch kein Codesatz ausgewählt wurde.

Die bind_textdomain_codesetFunktion kann mehrmals verwendet werden. Bei mehrmaliger Verwendung mit demselben Domainnamen-Argument überschreibt der spätere Aufruf die Einstellungen des früheren.

Die bind_textdomain_codesetFunktion gibt einen Zeiger auf eine Zeichenfolge zurück, die den Namen des ausgewählten Codesatzes enthält. Der String wird funktionsintern vergeben und darf vom Benutzer nicht verändert werden. Wenn das System während der Ausführung von bind_textdomain_codesetden Core verlassen hat , ist der Rückgabewert NULL und die globale Variable errno wird entsprechend gesetzt.

Sie könnten auch die native verwenden Unicode - Zeichenkategorien , die sprachunabhängig sind und die POSIX - Klassen ganz verzichten, oder vielleicht auf dem ehemaligen rufen Sie genügend Informationen , um die letztere zu definieren.

Neben Komplikationen bringt Unicode auch neue Möglichkeiten. Zum einen gehört jedes Unicode-Zeichen zu einer bestimmten Kategorie. Sie können ein einzelnes Zeichen der Kategorie "Buchstabe" mit zuordnen \p{L}. Sie können ein einzelnes Zeichen, das nicht zu dieser Kategorie gehört, mit abgleichen \P{L}.

Auch hier bedeutet "Zeichen" "Unicode-Codepunkt". \p{L}Entspricht einem einzelnen Codepunkt in der Kategorie "Buchstabe". Wenn Ihre Eingabezeichenfolge als à codiert ist U+0061 U+0300, stimmt sie aohne den Akzent überein . Wenn die Eingabe als àcodiert ist U+00E0, stimmt sie àmit dem Akzent überein . Der Grund ist, dass sowohl die Codepunkte U+0061 (a)als U+00E0 (à)auch in der Kategorie "Buchstabe" sind, während sie U+0300in der Kategorie "Marke" sind.

Sie sollten jetzt verstehen, warum \P{M}\p{M}*+das Äquivalent von ist \X. \P{M}Stimmt mit einem Codepunkt überein, der keine Kombinationsmarke ist, während \p{M}*+ null oder mehr Codepunkte übereinstimmen, die Marken kombinieren. Verwenden Sie, um einen Buchstaben mit diakritischen Zeichen abzugleichen \p{L}\p{M}*+. Dieser letzte reguläre Ausdruck stimmt immer überein à, unabhängig davon, wie er codiert ist. Der Possessive Quantifier stellt sicher, dass das Backtracking nicht dazu führt, dass \P{M}\p{M}*+eine Nicht-Marke ohne die darauf folgenden Kombinationsmarken abgeglichen wird, was \X niemals der Fall wäre.

Auf derselben Website, auf der die oben genannten Informationen bereitgestellt wurden, wird auch die Tcleigene POSIX- konforme Regex-Implementierung erläutert , die möglicherweise ein weiterer Weg ist, Ihr Ziel zu erreichen.

Und als letztes unter den Lösungen schlage ich vor, dass Sie die LC_COLLATEDatei selbst nach der vollständigen und in der Reihenfolge angeordneten Systemzeichentabelle abfragen können . Dies scheint nicht einfach zu sein, aber ich habe einige Erfolge erzielt, nachdem ich es localedefwie folgt kompiliert habe :

<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

Es ist zwar derzeit fehlerhaft, aber ich hoffe, es zeigt zumindest die Möglichkeit.

AUF DEN ERSTEN BLUSH

strings $_/en_GB

#OUTPUT

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

Es sah wirklich nicht nach viel aus, aber dann bemerkte ich die copyBefehle in der Liste. Die obige Datei scheint zum Beispiel copyin "en_US" zu sein, und eine andere wirklich große Datei , die sie alle zu einem gewissen Grad zu teilen scheinen, ist iso_14651_t1_common.

Es ist ziemlich groß:

strings $_ | wc -c

#OUTPUT
431545

Hier ist das Intro zu /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>;

...

Sie können grepdies natürlich durchmachen, aber Sie könnten einfach:

recode -lf gb

Stattdessen. Sie würden so etwas bekommen:

Dec  Oct Hex   UCS2  Mne  BS_4730

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

... UND MEHR

Es gibt auch ein luitUTF-8- ptyÜbersetzungsgerät für Endgeräte, das für XTerms ohne UTF-8-Unterstützung als Vermittler fungiert. Es verarbeitet eine Vielzahl von Schaltern - z. B. das Protokollieren aller konvertierten Bytes in einer Datei oder -cals einfacher |pipeFilter.

Ich habe nie bemerkt, dass es so viel zu diesem Thema gibt - die Locales und Charakterkarten und all das. Dies ist anscheinend eine sehr große Sache, aber ich denke, dass alles hinter den Kulissen weitergeht. Zumindest auf meinem System gibt es ein paar hundert man 3ähnliche Ergebnisse für die Suche nach Gebietsschemas.

Und auch da ist:

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

Das wird noch sehr lange dauern.

Die XlibFunktionen erledigen dies die ganze Zeit - dies luitist ein Teil dieses Pakets.

Die Tcl_uni...Funktionen könnten sich ebenfalls als nützlich erweisen.

nur ein wenig <tab>vervollständigen und mansuchen und ich habe ziemlich viel zu diesem Thema gelernt.

Mit localedef- können Sie die localesin Ihrem I18NVerzeichnis zusammenstellen. Die Ausgabe ist flippig und nicht außerordentlich nützlich - überhaupt nicht wie die charmaps- aber Sie können das Rohformat so wie oben angegeben erhalten, wie ich es getan habe:

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

Dann odkönnen Sie es mit lesen - Bytes und Strings:

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

Obwohl es noch ein langer Weg ist, einen Schönheitswettbewerb zu gewinnen, ist dies eine brauchbare Ausgabe. Und odist natürlich so konfigurierbar, wie Sie es möchten.

Ich denke, ich habe auch diese vergessen:

    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

Ich habe sie wahrscheinlich vergessen, weil ich sie nicht zur Arbeit bringen konnte. Ich benutze es nie Perlund ich weiß nicht, wie ich ein Modul richtig laden soll. Aber die manSeiten sehen ziemlich gut aus. In jedem Fall sagt mir etwas, dass es für Sie weniger schwierig ist, ein Perl-Modul aufzurufen als ich. Und auch diese befanden sich bereits auf meinem Computer - und ich verwende niemals Perl. Es gibt auch einige I18N, bei denen ich wehmütig gescrollt habe, weil ich wusste, dass ich sie auch nicht zum Arbeiten bringen würde.

mikeserv
quelle
1
Das sind alles sehr nette und nützliche Informationen, aber sie enthalten Informationen zu den Quelldateien (in i18n), die möglicherweise verwendet wurden, um das aktuell verwendete Gebietsschema zu generieren. Die Gebietsschemainformationen stammen wahrscheinlich von /usr/lib/locale/locale-archiveoder /some/dir/LC_CTYPE, und das ist der Teil, der für mein Gebietsschema relevant ist und in den Dateien gespeichert ist, nach denen ich suche.
Stéphane Chazelas
@StephaneChezales - extrahieren Sie einfach Ihre LC_STUFFaus dem Archiv mit localedef- es macht das auch. Das kann ich wohl auch testen. Das und so ziemlich alles andere können Sie auch mit stringsoder ododer dem Rest ansehen . Ich habe es trotzdem getan. Aber im Übrigen - das charmaps ist das Gebietsschema, das Sie derzeit verwenden - und darüber localedefwird auch berichtet. Auch das ist was auch recodetut.
mikeserv
Sie sagen im Grunde, dass wir die Abfrage von Zeichenklasseninformationen in den Systembibliotheken von Hand durchführen können. Dafür sind jedoch Tausende von Codezeilen erforderlich, und das Ergebnis ist systemspezifisch. (Parsen der Umgebung auf dieselbe Weise wie die Systembibliothek (LOCPATH, LANG, LANGUAGE, LC_CTYPE ...). Ich kann nicht feststellen, wo nach den Daten gesucht werden soll, und sie extrahieren ...) mit localedef obwohl.
Stéphane Chazelas
@StephaneChazelas - Ich schlage vor , Sie es nicht von Hand zu tun - ich schlage vor , Sie es mit einem Computer zu tun - System - Binärdateien mit wie od, recode, uconvund den Rest. Aber es war mein Fehler - es localedefextrahiert es nicht, es ist der recodeWille. Sie müssen auschecken info recode- und abgesehen von dem recodeTabellenbefehl, den ich zeige, gibt es fast das Gleiche - und es wird die Dinge auf die gleiche Weise behandeln, denke ich. Es zieht nicht nur Ihren Zeichensatz aus der Luft. Auf jeden Fall hatte ich große Hoffnungen auf diese perlModule - haben Sie welche ausprobiert?
mikeserv
1
Wenn es eine API zum Abrufen der Liste der Zeichen in einer bestimmten Zeichenklasse im aktuellen Gebietsschema gibt, ist dies genau das, wonach ich suche. Wenn Sie zeigen können, wie das geht, akzeptiere ich die Antwort. Das einzige, woran ich denken könnte (und wie ich in meiner Frage die "erwartete Ausgabe" erhalten habe), ist die Verwendung iswblank(3)für alle möglichen Zeichenwerte.
Stéphane Chazelas
1

Zumindest auf GNU-, FreeBSD- oder Solaris-Systemen funktioniert dieser Brute-Force-Ansatz:

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

Während es sich bei C / POSIX wchar_tum einen undurchsichtigen Typ handelt, der keine Beziehung zu Unicode hat und garantiert nur alle vom Gebietsschema des Systems unterstützten Zeichen abdeckt, entsprechen die Werte in der Praxis in den meisten Systemen, die Unicode unterstützen, den Unicode-Codepunkten und die Gebietsschemadefinitionen basieren selbst auf Unicode.

Unicode soll eine Obermenge aller bekannten Zeichensätze sein. Wenn Sie also alle gültigen Codepunkte in Unicode (0 bis 0xD7FF und 0xE000 bis 0x10FFFF) durchlaufen, sollten Sie mindestens alle Zeichen auflisten, die von einem bestimmten Zeichensatz unterstützt werden.

Hier verwenden wir die Standard-API für das Gebietsschema des Systems, um zu überprüfen, welche von einem bestimmten Typ sind, und um sie in ihre codierte Form in der Codierung des Gebietsschemas zu konvertieren. Wir verwenden perlund sein charnamesModul nur, um den Namen eines bestimmten Unicode-Codepunkts zu erhalten.

Bei Gebietsschemata, die zustandsbehaftete Codierungen wie ISO-2022-JP verwenden, stellen wir sicher, dass das codierte Formular von einem Standardausgangszustand aus angezeigt wird.

Ich habe kein System gefunden, auf dem Gebietsschemas mit einer statusbehafteten Zeichencodierung installiert waren, aber zumindest auf GNU-Systemen ist es möglich, einige zu generieren, damit ein falsches Gebietsschema erstellt werden kann (und zumindest funktionieren GNU-Tools in diesen nicht richtig Gebietsschemas). Mit einem benutzerdefinierten Gebietsschema, das ISO-2022-JP mit einem normalen ja_JPGebietsschema verwendet, erhalte ich beispielsweise Folgendes:

$ 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

Vergleichen mit:

$ 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 wechselt 1B 24 42sequence ( \e$B) von ASCII in einen Zustand, in dem Zeichen als 2 (7-Bit) Bytes ausgedrückt werden (hier 21 21 für diesen IDEOGRAPHIC SPACE). In EUCJP sind es die gleichen Bytes, aber die Zustandsumschaltung erfolgt durch Umdrehen des 8. Bits ( A1 = 21 | 0x80), wodurch es zustandsloser wird.

Das bedeutet, dass es in diesen zustandsbehafteten Codierungen mehrere Möglichkeiten gibt, ein bestimmtes Zeichen zu schreiben (z. B. durch Einfügen mehrerer dieser Zustandswechselsequenzen ), und die durch diesen obigen Code gezeigte Sequenz ist nur eine davon (die kanonische aus einer Initiale) Standardzustand).

Während bei einem normalen locale, Zeichen nicht außerhalb 0..0xD7FF, 0xE000..0x10FFFF, für eine sein können Rogue locale kann jedes Zeichen im Bereich von Wchar_t unterstützt werden. Beispielsweise könnte ich ein Gebietsschema erstellen, in dem U + DCBA- oder U + 12345678-Zeichen (oder Zeichen, wenn sie zulässig wären) Leerzeichen sind . Aus diesem Grund möchten Sie diesen Code kompilieren, -D SUPPORT_ROGUE_LOCALESum diese abzudecken. Das bedeutet jedoch, dass das Durchsuchen der gesamten Liste viel mehr Zeit in Anspruch nimmt.

Ich konnte @ mikeservs Lösung nicht verwenden, da sie recodeihre eigenen Konvertierungen verwendet, nicht länger gewartet wird und nur Unicode-Zeichen bis zu 0xFFFF unterstützt, und GNU trfunktioniert zumindest nicht mit Multi-Byte-Zeichen.

Ich konnte @ ChrisDown's nicht verwenden , da pythones keine Schnittstellen zu den POSIX-Zeichenklassen gibt.

Ich habe Perl ausprobiert, aber es ist falsch für Codepunkte zwischen 128 und 255 für Gebietsschemata mit mehreren Bytes außer UTF-8 und verwendet nicht die Konvertierungsbibliotheken des Systems.

Stéphane Chazelas
quelle
Ich denke, dies ist effektiv die einzige Möglichkeit, aber es gibt mehrere Probleme, angefangen mit der Tatsache, dass Sie Vorkenntnisse für die Festlegung des Bereichs der zulässigen Codepunkte verwendet haben. Wenn Sie einen Unicode-Charmap verwenden, sind die Zeichenklassen zumindest theoretisch unabhängig vom Skript (gemäß Unicode-Standard, nicht C-Ländereinstellungen), aber die "allgemeinen Unicode-Kategorien" sind auch nicht dieselben wie die C-Zeichenklassen. Übrigens enthalten die i18n-c-Typen von glibc zwei weitere Zeichenklassen: combiningund combining_level3(d. iswctype(i, wctype("combining"))
H.
@rici, siehe edit (und auch der frage).
Stéphane Chazelas