Программирование / [Из песочницы] UTF-8: Кодирование и декодирование

в 9:09, , рубрики: utf-8, vbscript, Юникод, метки: , ,

Причиной разобраться в том, как же работает UTF-8 и что такое Юникод заставил тот факт, что VBScript не имеет встроенных функций работы с UTF-8. А так как ничего рабочего не нашел, то пришлось писть/дописывать самому. Опыт на мой взгляд полезный в любом случае. Для лучшего понимания начну с теории.
О Юникоде

До появления Юникода широко использовались 8-битные кодировки, главные минусы которых очевидны:Всего 255 символов, да и то часть из них не графические;

Возможность открыть документ не с той кодировкой, в которой он был создан;

Шрифты необходимо создавать для каждой кодировки.


Так и было решено создать единый стандарт «широкой» кодировки, которая включала бы все символы (при чем сначала хотели в нее включить только обычные символы, но потом передумали и начали добавлять и экзотические). Юникод использует 1 112 064 кодовых позиций (больше чем 16 бит). Начало дублирует ANSII, а дальше остаток латиницы, кирилица, другие европейские и азиатские символы. Для обозначений символов используют шестнадцатеричную запись вида «U+xxxx» для первых 65k и с большим количеством цифр для остальных.
О UTF-8

Когда-то я думал что есть Юникод, а есть UTF-8. Позже я узнал, что ошибался.
UTF-8 является лишь представлением Юникода в 8-битном виде. Символы с кодами меньше 128 представляются одним байтом, а так как в Юникоде они повторяют ANSII, то текст написанный только этими символами будет являться текстом в ANSII. Символы же с кодами от 128 кодируются 2-мя байтами, с кодами от 2048 — 3-мя, от 65536 — 4-мя. Так можно было бы и до 6-ти байт дойти, но кодировать ими уже ничего.
0x00000000 — 0x0000007F: 0xxxxxxx
0x00000080 — 0x000007FF: 110xxxxx 10xxxxxx
0x00000800 — 0x0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
0x00010000 — 0x001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

Кодируем в UTF-8

Порядок действий примерно такой:Каждый символ превращаем в Юникод.

Проверяем из какого символ диапазона.

Если код символа меньше 128, то к результату добавляем его в неизменном виде.

Если код символа меньше 2048, то берем последние 6 бит и первые 5 бит кода символа. К первым 5 битам добавляем 0xC0 и получаем первый байт последовательности, а к последним 6 битам добавляем 0x80 и получаем второй байт. Конкатенируем и добавляем к результату.

Похожим образом можем продолжить и для больших кодов.

Function EncodeUTF8(s)

    Dim i, c, utfc, b1, b2, b3

   

    For i=1 to Len(s)

        c = AscW(Mid(s,i,1))

 

        If c < 128 Then  

            utfc = chr( c)  

        ElseIf c < 2048 Then

            b1 = c Mod &H40

            b2 = (c - b1) / &H40

            utfc = chr(&hc0 + b2) & chr(&h80 + b1)

        ElseIf c < 65536 Then

            b1 = c Mod &H40

            b2 = ((c - b1) / &H40) Mod &H40

            b3 = (c - b1 - (&H40 * b2)) / &H1000

            utfc = chr(&he0 + b3) & chr(&h80 + b2) & chr(&h80 + b1)

        End If

     

        EncodeUTF8 = EncodeUTF8 + utfc

    Next

End Function

Декодируем UTF-8
Ищем первый символ не меньший 128

Считаем все последующие байты вида 10xxxxxx

Если последовательность из двух байт и первый байт вида 110xxxxx, то отсекаем приставки и складываем, умножив первый байт на 0x40.

Аналогично для более длинных последовательностей.

Заменяем всю последовательность на нужный символ Юникода.

function DecodeUTF8(s)

    dim i, c, n, b1, b2, b3

    i = 1

    do while i <= len(s)

        c = asc(mid(s,i,1))

        if c and &H80 then

            n = 1

            do while i + n <= len(s)

                if (asc(mid(s,i+n,1)) and &HC0) &H80 then

                    exit do

                end if

                n = n + 1

            loop

            if n = 2 and ((c and &HE0) = &HC0) then

                b1 = asc(mid(s,i+1,1)) and &H3F

                b2 = c and &H1F

                c = b1 + b2 * &H40

            elseif n = 3 and ((c and &HF0) = &HE0) then

                b1 = asc(mid(s,i+2,1)) and &H3F

                b2 = asc(mid(s,i+1,1)) and &H3F

                b3 = c and &H0F

                c = b3 * &H1000 + b2 * &H40 + b1

            else

                c = 191

            end if

            s = left(s,i-1) + chrw( c) + mid(s,i+n)

        end if

        i = i + 1

    loop

    DecodeUTF8 = s

end function

Ссылки
Юникод на ВикипедииИсходник для ASP+VBScript

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js