คำสั่งเพื่อดึงรายการของอักขระในคลาสอักขระที่กำหนดในโลแคลปัจจุบัน


18

สิ่งที่อาจจะเป็นวิธีการที่จะดึงรายชื่อของตัวละครทุกตัวในชั้นเรียนตัวอักษรที่กำหนด (เช่นที่blank, alpha, digit... ) ในสถานที่ปัจจุบัน

ตัวอย่างเช่น

LC_ALL=en_GB.UTF-8 that-command blank

ในอุดมคติบนระบบ Debian ของฉันจะแสดงสิ่งที่ชอบ:

      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

และในโลแคล C สามารถแสดงสิ่งที่ชอบ:

09 U+0009 HORIZONTAL TAB
20 U+0020 SPACE

นั่นคือการเป็นตัวแทนของตัวละครในสถานที่ในแง่ของอาร์เรย์ของไบต์ (เช่น UTF-8 ในตัวอย่างแรกและไบต์เดียวในที่สอง), codepoint อักขระ Unicode เทียบเท่าและคำอธิบาย

บริบท

(แก้ไข) ตอนนี้ช่องโหว่ได้รับการแก้ไขและเปิดเผยเป็นเวลานานฉันสามารถเพิ่มบริบทได้เล็กน้อย

ฉันถามคำถามว่าในช่วงเวลาที่ผมกำลังสืบสวนCVE 2014-0475 glibcมีข้อบกพร่องในการที่จะให้ผู้ใช้ใช้สถานที่เช่นLC_ALL=../../../../tmp/evil-localeที่ได้รับการแก้ไขที่เกี่ยวข้องกับเส้นทางการค้นหาสถานที่เกิดเหตุระบบมาตรฐานและทำให้อนุญาตให้ใช้ไฟล์ใด ๆ ที่เป็นคำจำกัดความของสถานที่

ฉันจะสร้างสถานที่โกงเช่นกับ byte เดียวต่อตัวอักษร charset ที่ตัวละครส่วนใหญ่ยกเว้นs, hและอื่น ๆ น้อยได้รับการพิจารณาช่องว่างและที่จะทำให้การbashทำงานshในขณะที่การแยกวิเคราะห์ Debian ทั่วไป/etc/bash.bashrcไฟล์ (และที่สามารถนำมาใช้จะได้รับการเข้าถึงเปลือกบนgitเซิร์ฟเวอร์การโฮสต์สำหรับอินสแตนซ์ที่ให้ไว้bashใช้เป็นเชลล์การเข้าสู่ระบบของgitผู้ใช้เซิร์ฟเวอร์และsshเซิร์ฟเวอร์ยอมรับLC_*/ LANGตัวแปรและผู้โจมตีสามารถอัปโหลดไฟล์ไปยังเซิร์ฟเวอร์)

ตอนนี้ถ้าฉันเคยพบLC_CTYPE(นิยามสถานที่รวบรวม) ใน/tmp/evilฉันจะรู้ได้อย่างไรว่ามันเป็นอันธพาลและวิธีการที่

ดังนั้นเป้าหมายของฉันคือการยกเลิกการรวบรวมคำจำกัดความสถานที่เหล่านั้นและถ้าไม่อย่างน้อยก็รู้ว่าตัวละครใด (พร้อมกับการเข้ารหัสของพวกเขา) อยู่ในระดับตัวละครที่กำหนด

ดังนั้นในใจ:

  • โซลูชันที่ดูที่ไฟล์ต้นฉบับของโลแคล (คำจำกัดความของโลแคลเหมือนกับที่อยู่/usr/share/i18n/localeใน Debian) นั้นไม่มีประโยชน์ในกรณีของฉัน
  • คุณสมบัติอักขระ Unicode ไม่เกี่ยวข้อง ฉันสนใจเฉพาะสิ่งที่สถานที่นั้นพูด บนระบบ Debian แม้ระหว่างสองระบบโลแคล UTF-8 โดยที่คนอื่นโกงรายการของอักขระในคลาสอาจแตกต่างกัน
  • เครื่องมือชอบrecode, pythonหรือperlว่าทำไบต์ / หลายไบต์ / จากการแปลงตัวอักษรไม่สามารถนำมาใช้เป็นพวกเขาอาจจะ (และในทางปฏิบัติทำ) ให้การแปลงในทางที่แตกต่างจากสถานที่เกิดเหตุ

สำหรับสถานที่ส่วนใหญ่ในที่สุดมันก็มาจากสิ่งที่ LC_CTYPE ใน (พร้อม glibc) /usr/share/i18n/locales/i18n... ซึ่งแน่นอนมาจากฐานข้อมูล Unicode Character แน่นอนว่าจะเป็นการดีถ้ามีคำสั่ง
Derobert

@derobert ใช่ในขณะที่locale(อย่างน้อย GNU หนึ่ง) จะดึงข้อมูลจำนวนมากที่เก็บไว้ในหลายหมวดหมู่สิ่งที่ไม่สำคัญที่สุดใน LC_CTYPE และ LC_COLLATE ฉันสงสัยว่ามี API ซ่อนอยู่เพื่อดึงข้อมูลนั้นหรือไม่รวบรวมข้อมูลสถานที่
Stéphane Chazelas

ใช่ - คุณสามารถรับข้อมูลที่แยกวิเคราะห์ - ในที่สุดฉันก็ไปถึงเพื่อสรุปการแก้ไขของฉัน มีหลายคำสั่งที่คุณอาจติดตั้งแล้ว - อย่างน้อยฉันก็ทำและฉันไม่รู้ด้วยซ้ำ ฉันหวังว่ามันจะช่วย โดยเฉพาะrecodeและuconvสามารถให้สิ่งที่คุณพูดในสิ่งที่คุณต้องการ อาจเป็นไปได้แม้เพียงluitและodผมคิดว่า ...
mikeserv

ดีมาก! นั่นหมายความว่าคุณไม่ต้องการperlเลย
mikeserv

ดูเหมือนว่าฉันจะสามารถแยกชุดอักขระของฉันออกมาได้LC_CTYPEเพียงแค่od -A n -t c <LC_CTYPE | tsortคุณได้ลองไปแล้ว แต่ฉันไม่เคยได้ยินมาก่อนและฉันกำลังอ่านผ่านinfoและมันทำให้ฉันนึกถึงเรื่องนี้ - และดูเหมือนว่าจะใช้งานได้ นอกจากนี้ยังมีptxแต่ฉันคิดว่ามันมีความเกี่ยวข้องน้อยกว่า อย่างไรก็ตามหากคุณยังไม่ได้ลองและตัดสินใจที่จะทำเช่นนั้น - คำเตือนที่เป็นธรรม - มันต้องใช้ความอดทนเล็กน้อย lehman.cuny.edu/cgi-bin/man-cgi?tsort+1
mikeserv

คำตอบ:


7

ทางออกสุดท้ายที่เป็นไปได้

ดังนั้นฉันได้รับข้อมูลด้านล่างทั้งหมดแล้วมาพร้อมกับสิ่งนี้:

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

หมายเหตุ :

ฉันใช้odเป็นตัวกรองสุดท้ายด้านบนสำหรับการตั้งค่าและเพราะฉันรู้ว่าฉันจะไม่ทำงานกับอักขระหลายไบต์ซึ่งจะไม่สามารถจัดการได้อย่างถูกต้อง recode u2..dumpทั้งสองจะสร้างผลลัพธ์มากขึ้นเช่นเดียวกับที่ระบุในคำถามและจัดการกับอักขระที่กว้างอย่างถูกต้อง

เอาท์พุท

        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 ของ PROGRAMMER

ดังที่ฉันสาธิตด้านล่างrecodeจะให้แผนที่อักขระที่สมบูรณ์แก่คุณ ตามคู่มือของมันจะทำสิ่งนี้ตามค่าปัจจุบันของDEFAULT_CHARSETตัวแปรสภาพแวดล้อมหรือหากไม่สามารถทำงานได้ตามที่คุณระบุ:

เมื่อละเว้นชื่อชุดอักขระหรือเว้นว่างไว้ค่าของDEFAULT_CHARSETตัวแปรในสภาพแวดล้อมจะถูกนำมาใช้แทน หากไม่ได้กำหนดตัวแปรนี้ไว้recodeไลบรารีจะใช้การเข้ารหัสของโลแคลปัจจุบัน บนระบบที่สอดคล้องกับPOSIXสิ่งนี้ขึ้นอยู่กับค่าที่ไม่ว่างแรกระหว่างตัวแปรสภาวะแวดล้อมLC_ALL, LC_CTYPE, LANGและสามารถพิจารณาผ่านคำสั่งlocale charmap.

นอกจากนี้ที่น่าสังเกตrecodeก็คือ api :

โปรแกรมที่ชื่อว่าrecodeเป็นเพียงแอปพลิเคชันของไลบรารีการเข้ารหัส ไลบรารีการเข้ารหัสมีให้แยกต่างหากสำหรับโปรแกรม C อื่น ๆ วิธีที่ดีในการทำความคุ้นเคยกับไลบรารีการถอดรหัสคือทำความคุ้นเคยกับrecodeโปรแกรมเอง

ในการใช้ไลบรารีการเข้ารหัสเมื่อติดตั้งแล้วโปรแกรม C จำเป็นต้องมีบรรทัด:

#include <recode.h>

สำหรับการเปรียบเทียบสตริงที่เป็นมิตรกับสากลPOSIXและCมาตรฐานกำหนดstrcoll()ฟังก์ชัน:

strcoll()ฟังก์ชั่นจะเปรียบเทียบสตริงชี้ไปตามs1สตริงชี้ไปตามs2ทั้งตีความตามความเหมาะสมกับหมวดหมู่ LC_COLLATE ของสถานที่ปัจจุบัน

strcoll()ฟังก์ชั่นจะไม่เปลี่ยนการตั้งค่าของ errno ถ้าประสบความสำเร็จ

เนื่องจากไม่มีค่าตอบแทนถูกสงวนไว้เพื่อระบุข้อผิดพลาดแอปพลิเคชันที่ต้องการตรวจสอบสถานการณ์ข้อผิดพลาดควรตั้งค่า errno เป็น 0 จากนั้นโทร strcoll()แล้วตรวจสอบ errno

นี่คือแยกกันอยู่เป็นตัวอย่างของการใช้งาน:

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

เกี่ยวกับPOSIXคลาสของตัวละครคุณได้ระบุว่าคุณใช้CAPI เพื่อค้นหาสิ่งเหล่านี้แล้ว สำหรับอักขระ Unicode และคลาสคุณสามารถใช้ชุดอักขระrecode's dump-with-namesเพื่อรับเอาต์พุตที่ต้องการ จากคู่มืออีกครั้ง :

ตัวอย่างเช่นคำสั่งrecode l2..full < inputหมายถึงการแปลงที่จำเป็นจากLatin-2ถึงUCS-2เนื่องจากการเชื่อมต่อdump-with-namesมีเพียงการเชื่อมต่อจากUCS-2 เท่านั้น ในกรณีดังกล่าวrecodeไม่แสดงต้นฉบับ ภาษาละติน-2รหัสในการถ่ายโอนข้อมูลเพียงที่สอดคล้องUCS 2ค่า เพื่อให้ตัวอย่างง่ายกว่าคำสั่ง

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

สร้างเอาต์พุตต่อไปนี้:

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)

ความคิดเห็นเชิงพรรณนามีให้ในภาษาอังกฤษและ ASCII แต่หากคำอธิบายภาษาอังกฤษไม่พร้อมใช้งาน แต่เป็นภาษาฝรั่งเศสคำอธิบายภาษาฝรั่งเศสจะได้รับแทนโดยใช้ Latin-1 อย่างไรก็ตามหาก ตัวแปรLANGUAGEหรือLANGสภาพแวดล้อมเริ่มต้นด้วยตัวอักษรfrการตั้งค่าการแสดงรายการจะเป็นภาษาฝรั่งเศสเมื่อทั้งสองคำอธิบายพร้อมใช้งาน

การใช้ไวยากรณ์ที่คล้ายกับข้างบนรวมกับชุดข้อมูลการทดสอบที่รวมอยู่ฉันสามารถใช้ผังตัวละครของฉันเองด้วย:

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

เอาท์พุท

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)

แต่สำหรับตัวละครทั่วไปrecodeดูเหมือนว่าไม่จำเป็น สิ่งนี้จะให้ชื่อตัวอักษรสำหรับทุกสิ่งในชุดอักขระขนาด 128 ไบต์:

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

เอาท์พุท

 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

แน่นอนมีเพียง 128- ไบต์เท่านั้นที่แสดง แต่นั่นเป็นเพราะ locale ของฉัน, utf-8 charmaps หรือไม่, ใช้ชุดอักขระASCIIและไม่มีอะไรเพิ่มเติม นั่นคือทั้งหมดที่ฉันได้รับ ถ้าฉันวิ่งโดยไม่ต้องluitกรองมันodจะม้วนกลับมาและพิมพ์แผนที่เดียวกันอีกครั้ง\0400.

มีสองปัญหาที่สำคัญกับวิธีการข้างต้นแม้ว่า อันดับแรกมีการเรียงลำดับของระบบ - สำหรับตำแหน่งที่ไม่ใช่ ASCII ค่าการกัดสำหรับชุดอักขระไม่ได้เป็นเพียงแค่ในseqสิ่งที่ฉันคิดว่าน่าจะเป็นแกนหลักของปัญหาที่คุณกำลังพยายามแก้ไข

tr's manหน้าGNU ระบุว่ามันจะขยาย[:upper:] [:lower:]ชั้นเรียนตามลำดับ - แต่นั่นก็ไม่มาก

ฉันจินตนาการว่าโซลูชันหนัก ๆ สามารถใช้งานได้sortแต่นั่นเป็นเครื่องมือที่ค่อนข้างลำบากสำหรับ API การเขียนโปรแกรมส่วนหลัง

recodeจะทำสิ่งนี้อย่างถูกต้อง แต่คุณไม่ได้รักโปรแกรมมากเกินไปเมื่อวันก่อน บางทีการแก้ไขในวันนี้อาจทำให้เกิดแสงที่เป็นมิตรมากกว่านี้หรืออาจจะไม่

GNU ยังมีgettextห้องสมุดฟังก์ชั่นและดูเหมือนว่าจะสามารถแก้ไขปัญหานี้ได้อย่างน้อยสำหรับLC_MESSAGESบริบท:

- ฟังก์ชั่น: char * bind_textdomain_codeset( const char *domainname, const char *codeset)

bind_textdomain_codesetฟังก์ชั่นสามารถนำมาใช้เพื่อระบุตัวอักษรชุดเอาท์พุแคตตาล็อกข้อความสำหรับโดเมน DOMAINNAME codesetอาร์กิวเมนต์ต้องเป็นที่ถูกต้องcodesetชื่อซึ่งสามารถใช้สำหรับiconv_openฟังก์ชั่นหรือตัวชี้โมฆะ

หากcodesetพารามิเตอร์เป็นตัวชี้ null ที่bind_textdomain_codeset ส่งกลับเลือกในปัจจุบันcodesetสำหรับโดเมนที่มีชื่อ DOMAINNAME มันกลับ NULL ถ้าไม่มีcodesetยังไม่ได้รับเลือก

bind_textdomain_codesetฟังก์ชั่นสามารถนำมาใช้หลายครั้ง หากใช้หลายครั้งด้วยอาร์กิวเมนต์ domainname เดียวกันการโทรในภายหลังจะแทนที่การตั้งค่าที่ทำไว้ก่อนหน้านี้

bind_textdomain_codesetฟังก์ชั่นกลับชี้ไปสตริงที่มีชื่อของ codeset ที่เลือก สตริงถูกจัดสรรภายในในฟังก์ชันและต้องไม่ถูกเปลี่ยนแปลงโดยผู้ใช้ หากระบบออกจากแกนระหว่างการดำเนิน bind_textdomain_codesetการค่าส่งคืนจะเป็น NULL และตั้งค่าตัวแปรโลก errno ตามลำดับ

คุณอาจใช้หมวดหมู่อักขระ Unicodeดั้งเดิมซึ่งเป็นภาษาที่ไม่ขึ้นต่อกันและนำหน้าคลาส POSIX ไปด้วยกันหรืออาจจะเรียกใช้ในอดีตเพื่อให้ข้อมูลเพียงพอที่จะให้คำจำกัดความหลัง

นอกเหนือจากภาวะแทรกซ้อน Unicode ยังนำความเป็นไปได้ใหม่ ๆ หนึ่งคืออักขระ Unicode แต่ละตัวอยู่ในหมวดหมู่ที่แน่นอน คุณสามารถตรงกับตัวอักษรตัวเดียวที่อยู่ในหมวดหมู่ "ตัวอักษร" \p{L}ด้วย \P{L}คุณสามารถตรงกับตัวอักษรตัวเดียวที่ไม่ได้อยู่ในหมวดหมู่ที่มี

อีกครั้ง "ตัวอักษร" หมายถึง "จุดรหัส Unicode" จริงๆ \p{L}ตรงกับจุดรหัสเดียวในหมวดหมู่ "จดหมาย" หากสตริงการป้อนข้อมูลของคุณถูกà เข้ารหัสเป็นสตริงจะU+0061 U+0300จับคู่aโดยไม่มีเครื่องหมายเน้นเสียง หากอินพุตถูกàเข้ารหัสเป็นU+00E0มันจะตรงàกับสำเนียง เหตุผลก็คือทั้งจุดรหัสU+0061 (a)และU+00E0 (à)อยู่ในหมวดหมู่ "ตัวอักษร" ในขณะที่U+0300อยู่ในหมวดหมู่ "เครื่องหมาย"

ตอนนี้คุณควรเข้าใจว่าทำไมเป็นเทียบเท่าของ \P{M}\p{M}*+ จับคู่จุดรหัสที่ไม่ใช่เครื่องหมายการรวมขณะที่ จับคู่จุดศูนย์หรือมากกว่านั้นที่รวมเครื่องหมาย เพื่อให้ตรงกับตัวอักษรรวมทั้งกำกับใด ๆ การใช้งาน regex สุดท้ายนี้จะจับคู่เสมอไม่ว่าจะเข้ารหัสอย่างไร Quantifier ที่เป็นเจ้าของทำให้แน่ใจว่าการย้อนรอยไม่ทำให้เกิดการจับคู่ที่ไม่ใช่เครื่องหมายหากไม่มีเครื่องหมายรวมที่ตามมาซึ่ง จะไม่มีวันทำ\X\P{M}\p{M}*+\p{L}\p{M}*+à\P{M}\p{M}*+\X

เว็บไซต์เดียวกับที่ให้ข้อมูลข้างต้นยังกล่าวถึงการติดตั้ง regex ที่สอดคล้องกับPOSIXTclของตัวเองซึ่งอาจเป็นอีกวิธีหนึ่งในการบรรลุเป้าหมายของคุณ

และสุดท้ายในบรรดาวิธีการแก้ปัญหาฉันจะแนะนำให้คุณสอบปากคำLC_COLLATEตัวไฟล์เองสำหรับการแม็พอักขระระบบที่สมบูรณ์และตามลำดับ สิ่งนี้อาจดูไม่ง่ายนัก แต่ฉันก็ประสบความสำเร็จด้วยการรวบรวมlocaledefดังต่อไปนี้

<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

เป็นที่ยอมรับในปัจจุบันมีข้อบกพร่อง แต่ฉันหวังว่ามันจะแสดงให้เห็นถึงความเป็นไปได้อย่างน้อย

ในการปัดแก้มครั้งแรก

strings $_/en_GB

#OUTPUT

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

มันดูเหมือนไม่มาก แต่แล้วฉันก็เริ่มสังเกตเห็นcopyคำสั่งตลอดรายการ ไฟล์ดังกล่าวดูเหมือนว่าจะcopyอยู่ใน"en_US"และอีกไฟล์ใหญ่จริงที่ดูเหมือนว่าพวกเขาทั้งหมดแชร์ในระดับiso_14651_t1_commonหนึ่ง

มันค่อนข้างใหญ่:

strings $_ | wc -c

#OUTPUT
431545

นี่คือคำนำของ/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>;

...

คุณสามารถgrepผ่านหลักสูตรนี้ได้ แต่คุณอาจจะ:

recode -lf gb

แทน. คุณจะได้รับสิ่งนี้:

Dec  Oct Hex   UCS2  Mne  BS_4730

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

... และอื่น ๆ

นอกจากนี้ยังluitมีptyอุปกรณ์แปลเทอร์มินัล UTF-8 ฉันเดาว่าจะทำหน้าที่เป็นไประหว่าง XTerms โดยไม่รองรับ UTF-8 มันจัดการกับสวิตช์มากมาย - เช่นการบันทึกไบต์ที่ถูกแปลงทั้งหมดไปยังไฟล์หรือ-cเป็น|pipeตัวกรองอย่างง่าย

ฉันไม่เคยรู้เลยว่ามันมีอะไรมากมาย - สถานที่และแผนที่ตัวละครและทุกสิ่ง เห็นได้ชัดว่านี่เป็นเรื่องใหญ่มากแต่ฉันคิดว่าทุกอย่างจะดำเนินไปในเบื้องหลัง มีอย่างน้อยในระบบของฉันมีสองสามร้อยman 3ผลลัพธ์ที่เกี่ยวข้องสำหรับการค้นหาที่เกี่ยวข้องกับสถานที่เกิดเหตุ

และยังมี:

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

ว่าจะไปหามากยาวในขณะที่

Xlibฟังก์ชั่นการจัดการนี้ตลอดเวลา - luitเป็นส่วนหนึ่งของแพคเกจที่

Tcl_uni...ฟังก์ชั่นอาจพิสูจน์ประโยชน์เช่นกัน

เพิ่ง<tab>เสร็จสิ้นเล็กน้อยและmanการค้นหาและฉันได้เรียนรู้มากมายในเรื่องนี้

ด้วยlocaledef- คุณสามารถรวบรวมlocalesในI18Nไดเรกทอรีของคุณ ผลลัพธ์เป็นเรื่องขี้ขลาดและไม่มีประโยชน์เป็นพิเศษ - ไม่เหมือนcharmapsแต่อย่างใด - แต่คุณสามารถรับรูปแบบ raw ตามที่คุณระบุข้างต้นเหมือนที่ฉันทำ:

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

จากนั้นodคุณสามารถอ่านได้ - ไบต์และสตริง:

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

แม้ว่ามันจะห่างไกลจากการชนะการประกวดความงาม และodสามารถปรับแต่งได้ตามที่คุณต้องการแน่นอน

ฉันเดาว่าฉันลืมเรื่องเหล่านี้ด้วย:

    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

ฉันอาจลืมเกี่ยวกับพวกเขาเพราะฉันไม่สามารถทำงานได้ ฉันไม่เคยใช้Perlและไม่รู้วิธีการโหลดโมดูลอย่างถูกต้องฉันเดา แต่manหน้าดูดีทีเดียว ไม่ว่าในกรณีใดจะมีบางอย่างบอกฉันว่าคุณจะพบว่าการเรียกโมดูล Perl อย่างน้อยก็น้อยยากกว่าที่ฉันทำและอีกครั้งสิ่งเหล่านี้อยู่ในคอมพิวเตอร์ของฉันแล้ว - และฉันก็ไม่เคยใช้ Perl นอกจากนี้ยังมีบางส่วนI18Nที่ฉันเลื่อนดูด้วยความรู้เต็มว่าฉันจะไม่ทำให้พวกเขาทำงาน


1
นั่นเป็นข้อมูลที่ดีและมีประโยชน์ทั้งหมด แต่นั่นให้ข้อมูลเกี่ยวกับไฟล์ต้นฉบับ (ในi18n) ที่อาจจะใช่หรือไม่ใช่อาจใช้เพื่อสร้างสถานที่ที่ฉันใช้อยู่ในปัจจุบัน ข้อมูลสถานที่อาจมาจาก/usr/lib/locale/locale-archiveหรือ/some/dir/LC_CTYPEนั่นคือส่วนที่เกี่ยวข้องกับสถานที่ของฉันที่เก็บไว้ในไฟล์เหล่านั้นที่ฉันติดตาม
Stéphane Chazelas

@StephaneChezales - เพียงแค่ดึงข้อมูลของคุณLC_STUFFออกจากไฟล์เก็บถาวรด้วยlocaledef- ก็ทำได้เช่นกัน ฉันสามารถสาธิตได้เช่นกันฉันเดา คุณยังสามารถดูสิ่งนั้นและทุกอย่างอื่นที่มีstringsหรือodส่วนที่เหลือ ฉันก็ทำเช่นนั้น แต่โดยวิธีการ - The charmaps มี youre สถานที่ปัจจุบันใช้ - และlocaledefจะรายงานเช่นกันว่า ยังเป็นสิ่งที่recodeทำเกินไป
mikeserv

คุณบอกว่าเราสามารถทำสิ่งที่ห้องสมุดของระบบใช้ในการสืบค้นข้อมูลคลาสอักขระ แต่นั่นจะต้องมีโค้ดหลายพันบรรทัดในการทำเช่นนั้นได้อย่างน่าเชื่อถือและผลลัพธ์จะเป็นระบบที่เฉพาะเจาะจง (แยกวิเคราะห์สภาพแวดล้อมแบบเดียวกับที่ห้องสมุดระบบทำ (LOCPATH, LANG, LANGUAGE, LC_CTYPE ... ระบุตำแหน่งที่จะค้นหาข้อมูลแยกมันออกมา ... ) ฉันไม่เห็นวิธีดึงข้อมูลจากไฟล์เก็บถาวร กับ localedef แม้ว่า
Stéphane Chazelas

@StephaneChazelas - ฉันไม่แนะนำให้คุณทำด้วยมือ - ผมขอแนะนำให้คุณทำมันด้วยคอมพิวเตอร์ - ใช้ไบนารีของระบบเช่นod, recode, uconvและส่วนที่เหลือ แต่มันเป็นความผิดพลาดของฉัน - ไม่ใช่localedefว่ามันrecodeจะแยกออกมา คุณต้องเช็คเอาท์info recode- และนอกเหนือจากrecodeคำสั่งตารางที่ฉันแสดงมีสิ่งเดียวกัน - และมันจะจัดการกับสิ่งต่าง ๆ ในลักษณะเดียวกันฉันคิดว่า ไม่เพียงดึงชุดอักขระของคุณออกมาจากอากาศ ในกรณีใด ๆ ฉันมีความหวังสูงสำหรับperlโมดูลเหล่านั้น- คุณลองทำอะไรบ้าง?
mikeserv

1
หากมี API เพื่อดึงรายชื่อของตัวละครในคลาสตัวละครที่กำหนดในสถานที่ปัจจุบันนั่นคือสิ่งที่ฉันกำลังมองหาโดยเฉพาะ หากคุณสามารถแสดงให้เห็นถึงวิธีการทำเช่นนี้ฉันจะยอมรับคำตอบ สิ่งเดียวที่ฉันคิดได้ (และวิธีที่ฉันได้รับ "ผลลัพธ์ที่คาดหวัง" ในคำถามของฉัน) คือการใช้iswblank(3)สำหรับค่าอักขระที่เป็นไปได้ทั้งหมด
Stéphane Chazelas

1

อย่างน้อยในระบบ GNU, FreeBSD หรือ Solaris วิธีการบังคับแบบเดรัจฉานนี้ทำงาน:

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

ในขณะที่ต่อ C / POSIX wchar_tเป็นประเภททึบแสงที่ไม่มีความสัมพันธ์กับ Unicode และรับประกันว่าจะครอบคลุมอักขระทั้งหมดที่รองรับโดยโลแคลของระบบในทางปฏิบัติในระบบส่วนใหญ่ที่รองรับ Unicode ค่าจะสอดคล้องกับจุดโค้ด Unicode และนิยามของโลแคลนั้นขึ้นอยู่กับ Unicode

Unicode นั้นมีความหมายว่าเป็น superset ของ charsets ที่รู้จักทั้งหมดดังนั้นให้วนลูปที่ถูกต้องทั้งหมดใน Unicode (0 ถึง 0xD7FF และ 0xE000 ถึง 0x10FFFF) ควรแสดงรายการอักขระทั้งหมดที่สนับสนุนโดย charset ที่กำหนด

ที่นี่เราใช้ API มาตรฐานของระบบเพื่อตรวจสอบว่ามีประเภทใดและแปลงเป็นรูปแบบที่เข้ารหัสในการเข้ารหัสของสถานที่ เราใช้perlและcharnamesโมดูลของมันเท่านั้นที่จะได้รับชื่อจาก codepoint Unicode ที่กำหนด

ในสถานที่ที่ใช้การเข้ารหัส stateful เช่น ISO-2022-JP เราตรวจสอบให้แน่ใจว่ารูปแบบที่เข้ารหัสถูกแสดงจากสถานะเริ่มต้นเริ่มต้น

ฉันไม่พบระบบที่ติดตั้งโลแคลด้วยการเข้ารหัสอักขระ stateful แต่อย่างน้อยในระบบ GNU เป็นไปได้ที่จะสร้างบางอย่างดังนั้นโลแคล rogue สามารถทำได้ (และอย่างน้อยเครื่องมือ GNU ไม่ทำงานอย่างถูกต้อง สถานที่) ตัวอย่างเช่นด้วยโลแคลที่กำหนดเองที่ใช้ ISO-2022-JP กับja_JPโลแคลปกติฉันได้รับ:

$ 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

เปรียบเทียบกับ:

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

ใน ISO-2022-JP 1B 24 42ลำดับ ( \e$B) สลับจาก ASCII ไปเป็นสถานะที่อักขระถูกแสดงเป็น 2 (7 บิต) ไบต์ (ที่นี่ 21 21 สำหรับ IDEOGRAPHIC SPACE นั้น) ในขณะที่ EUCJP เป็นไบต์เดียวกัน แต่การสลับสถานะทำได้โดยการเปิดบิตที่ 8 ( A1 = 21 | 0x80) ซึ่งทำให้ไร้สัญชาติมากขึ้น

นั่นหมายความว่าในการเข้ารหัส stateful เหล่านั้นมีหลายวิธีในการเขียนตัวละครที่กำหนด (ตัวอย่างเช่นโดยการแทรกหลายลำดับการเปลี่ยนสถานะเหล่านั้น) และลำดับที่แสดงโดยรหัสดังกล่าวข้างต้นเป็นเพียงหนึ่งในพวกเขา สถานะเริ่มต้น)

สำหรับโลแคลปกติอักขระไม่สามารถอยู่นอก 0..0xD7FF, 0xE000..0x10FFFF สำหรับโลแคลrogueอักขระใด ๆ ในช่วงที่สนับสนุนโดย wchar_t อาจเป็น ยกตัวอย่างเช่นฉันจะสร้างสถานที่ U + DCBA หรือ U + 12345678 ตัวอักษร (หรือจะเป็นตัวละครที่ว่าพวกเขาได้รับอนุญาต) มีช่องว่าง นั่นเป็นเหตุผลที่คุณต้องการรวบรวมรหัสนั้น-D SUPPORT_ROGUE_LOCALESเพื่อครอบคลุมรหัสเหล่านั้นซึ่งหมายความว่าใช้เวลาในการสแกนรายการทั้งหมดมากขึ้น

ฉันไม่สามารถใช้โซลูชันของ @ mikeserv ได้เนื่องจากrecodeใช้การแปลงของตัวเองแล้วจะไม่ได้รับการดูแลรักษาอีกต่อไปและรองรับเฉพาะอักขระ Unicode ไม่เกิน 0xFFFF และtrอย่างน้อยGNU ไม่สามารถใช้กับอักขระแบบหลายไบต์ได้

ฉันไม่สามารถใช้@ ChrisDownเนื่องจากpythonไม่มีส่วนติดต่อกับคลาสอักขระ POSIX

ฉันลอง Perl แต่มันปลอมสำหรับจุดโค้ดระหว่าง 128 และ 255 สำหรับโลแคลหลายไบต์นอกเหนือจาก UTF-8 และไม่ใช้ไลบรารี่การแปลงของระบบ


ฉันคิดว่านี่เป็นวิธีเดียวที่ทำได้อย่างมีประสิทธิภาพ แต่มันก็มีปัญหาจากหลาย ๆ ปัญหาเริ่มต้นจากความจริงที่ว่าคุณใช้ความรู้ก่อนหน้าเพื่อตัดสินใจเกี่ยวกับช่วงของ codepoints ทางกฎหมาย อย่างน้อยก็ในทางทฤษฎีถ้าคุณใช้ Unicode charmap คลาสของตัวอักษรนั้นไม่ขึ้นอยู่กับสคริปต์ (ตามมาตรฐานของ Unicode ไม่ใช่ที่ตั้ง C) แต่ Unicode "หมวดหมู่ทั่วไป" นั้นไม่เหมือนกับคลาสตัวอักษร C BTW, i18n ctypes ของ glibc ประกอบด้วยคลาสอักขระเพิ่มอีกสองคลาส: combiningและcombining_level3(viz. iswctype(i, wctype("combining")))
rici

@rici ดูการแก้ไข (และคำถาม)
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.