WTF-8

 Возник вопрос печати текста в консоли:


Не проблема, в PureBasic написал код, символы взял из таблицы CP8666 . Для FreePascal оказалось все сложнее и пришлось переводить символы в UTF-8. Поэтому пришлось вернуться к перекодировке Unicode->UTF-8. Пошарил по страницам и написал код, проверил - работает. Занялся обратным преобразованием UTF-8->Unicode и нашел упоминание о другой длине байтов - не 4, как написано в  документации, а 5 или 6. И на этой длине я залип - нет подходящих данных для перекодировки, некоторые значения отличаются друг от друга. Поискал примеры и плюнул на решение задачи, добавив к своей программе дополнительную опцию - вывод сочетания UTF-8.


Осталось ждать появления проблемных символов.

Unicode->UTF-8

Procedure.s h2s(a.a)
  ProcedureReturn RSet(Hex(a),2,"0")+" "
EndProcedure
Procedure.s un2u8(c)
  r$=""
  ; 1st byte 2nd byte 3rd byte 4th byte code points
  ; 0xxxxxxx                                0-127 xxxxxxx 7 bits
  ; 110xxxxx 10xxxxxx                      128-2047 yyyyyxxxxxx 11bits
  ; 1110xxxx 10xxxxxx 10xxxxxx            2048-65535 zzzzyyyyyyxxxxxx 16 bits
  ; 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 00010000 – 001FFFFF 21 bits
  ; 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx $200000 – $3FFFFFF 26 bits
  ; 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 04000000 – 7FFFFFFF 21 bits
  
  If c<128
    r$=h2s(c)
  ElseIf c<2048
    r$=h2s( $C0+(c>>6)&$1F ) + h2s( $80+(c&$3F))
  ElseIf c<65536
    r$=h2s($E0+((c>>12)&$0F)) + h2s($80+((c>>6)&$3F)) + h2s($80+(c&$3F))
  ElseIf c<=$1FFFFF
    r$=h2s($F0+((c>>18)&7)) + h2s($80+((c>>12)&$3F)) + h2s($80+((c>>6)&$3F)) + h2s($80+(c&$3F))
  ElseIf c<=$3FFFFFF;111110xx must be wrong
    r$=h2s($F8 | (c >> 24))
    r$=r$+h2s($80 | ((c >> 18) & $3F))
    r$=r$+h2s($80 | ((c >> 12) & $3F))
    r$=r$+h2s($80 | ((c >> 6) & $3F))
    r$=r$+h2s($80 | (c & $3F))
  ElseIf c<=$7FFFFFFF
    r$=h2s($FC | ((c >> 30) & 1))
    r$=r$+h2s($80 | ((c >> 24) & $3F))
    r$=r$+h2s($80 | ((c >> 18) & $3F))
    r$=r$+h2s($80 | ((c >> 12) & $3F))
    r$=r$+h2s($80 | ((c >> 6) & $3F))
    r$=r$+h2s($80 | (c & $3F))
  EndIf
  
  Debug Hex(c)+" "+r$
  ProcedureReturn r$
EndProcedure
un2u8($10FFFF);F4 8F BF BF
un2u8(65536);0xF0 0x90 0x80 0x80
un2u8($1F4A2);0xF0 0x9F 0x92 0xA2
un2u8($2564);╤ 0xE2 0x95 0xA4
un2u8(2047);2047=0xDF 0xBF
un2u8($401);Ё d0 81
un2u8($30c4);0xE3 0x83 0x84
un2u8($11170);0xF0 0x91 0x85 0xB0
un2u8($FA00);0xEF 0xA8 0x80
un2u8($200000);F8 88 80 80 80
un2u8($3FFFFFF);FB BF BF BF BF
un2u8($7FFFFFFF); FD BF BF BF BF BF


UTF-8->Unicode
; 1st byte 2nd byte 3rd byte 4th byte code points
; 0xxxxxxx                                0-127 xxxxxxx
; 110yyyyy 10xxxxxx                      128-2047 yyyyyxxxxxx
; 1110zzzz 10yyyyyy 10xxxxxx            2048-65535 zzzzyyyyyyxxxxxx
; 11110www 10zzzzzz 10yyyyyy 10xxxxxx 65536+     wwwzzzzzzyyyyyyxxxxxx
;                                                    534210FEDCBA976543210       if ( (c & 0x80) == 0 )
Procedure unic(c.s)
  
  c0=Asc(Mid(c,1,1))
  c1=Asc(Mid(c,2,1))
  c2=Asc(Mid(c,3,1))
  c3=Asc(Mid(c,4,1))
  c4=Asc(Mid(c,5,1))
  c5=Asc(Mid(c,6,1))
  
  If c0 & $80 = 0
    wc=c0
  ElseIf c0 & $E0=$C0
    wc = (c0 & $1F) << 6;
    wc =wc|(c1 & $3F)
  ElseIf c0 & $F0 = $E0
    wc = (c0 & $0F) << 12;
    wc =wc|(c1 & $3F) << 6
    wc =wc|(c2 & $3F);
  ElseIf c0 & $F8 = $F0
    wc = (c0 & 07) << 18;
    wc =wc|(c1 & $3F) << 12;
    wc =wc|(c2 & $3F) << 6
    wc =wc|(c3 & $3F)
  ElseIf (c0 & $FC) = $F8
    wc = (c0 &3) << 24
    wc =wc|(c1&$3F) << 18
    wc =wc|(c2&$3F) << 12
    wc =wc|(c3&$3F) << 6
    wc =wc|(c4&$3F)
  ElseIf c0 & $FE= $FC
    wc = (c0&1) << 30
    wc =wc|(c1&$3F) << 24
    wc =wc|(c2&$3F) << 18
    wc =wc|(c3&$3F) << 12
    wc =wc|(c4&$3F) << 6
    wc =wc|(C5&$3F)
  EndIf
  ProcedureReturn wc          
EndProcedure

;Debug Hex(unic(Chr($41)),#PB_Long)
;Debug Hex(unic(Chr($c3)+Chr($b6)),#PB_Long);F6
;Debug Hex(unic(Chr($E2)+Chr($82)+Chr($AC)),#PB_Long);20ac
;Debug Hex(unic(Chr($F0)+Chr($9D)+Chr($84)+Chr($9E)),#PB_Long);1D11E
;https://wiki.tcl-lang.org/page/Encoding+Translations+and+i18n
;Debug Hex(unic(Chr($FD)+Chr($BF)+Chr($BF)+Chr($BF)+Chr($BF)+Chr($BF)),#PB_Long); must be 7FFFFFFF
;Debug Hex(unic(Chr($FB)+Chr($BF)+Chr($BF)+Chr($BF)+Chr($BF)),#PB_Long); must be 3FFFFFFF
;Debug Hex(unic(Chr($F7)+Chr($BF)+Chr($BF)+Chr($BF)),#PB_Long); must be 1FFFFFFF

Комментарии