UNICODE, API и ENTITY

Программирование на Active Server Pages и VBScript.
skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

UNICODE, API и ENTITY

Сообщение skiperski » 18.02.2006 (Сб) 12:33

Благодаря подсказке GSerg'а в топике "Как преобразовать относительный URL в абсолютный?" выяснилось, что большинство функций для работы с путями и линками уже существуют, а я, ничего не зная о них, изобретал велосипед. Тогда я озаботился поиском функции конвертирования строки с entities в строку unicode и нифига не нашёл.

Во-первых, почему в этот раздел форума. Т.к. в основном эта функция необходима при получении запроса на поиск или данных для сохранения на сервере, потому ASP.

Во-вторых, чтобы не засоряли топик советами применить StrConv(), MultiByteToWideChar(), WideCharToMultiByte() и иже с ними. Это всё не то, что нужно.

Что же нужно? На входе имеем строку с entities. Т.е., если символ не входит в состав текущей кодовой страницы, то он приходит на сервер в виде &#symbol_unicode; или &symbol_entity;. На выходе хочется иметь строку в unicode для сохранения её в БД или же для подстановки в параметры поиска (в той же БД).

Я ищу именно готовое решение с применением API, т.к. самостоятельно я такое когда-то писал (работало очень медленно и я не уверен, что охватывал все варианты этих титей :) ). Может быть у кого-то будет не API, но оригинальное и более-менее универсальное решение, то прошу тоже поделиться им.

Список entities можно посмотреть здесь.

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 18.02.2006 (Сб) 12:47

Пример строки можно? На входе и на выходе :roll:
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 18.02.2006 (Сб) 12:59

На вдохе:
Reisebüro или Reisebüro или Reisebüro

На выдохе:
Reisebüro Reisebüro Reisebüro

Третий вариант (шестнадцатиричный) практически не встречается, но теоретически может быть.

Только написал это, как обнаружил в тексте этой самой (и каждой) страницы форума такое вот:
Код: Выделить всё
&#x0412;&#x044B; <b>&#x043C;&#x043E;&#x0436;&#x0435;&#x0442;&#x0435;</b> &#x0434;&#x043E;&#x0431;&#x0430;&#x0432;&#x043B;&#x044F;&#x0442;&#x044C; &#x043F;&#x0440;&#x0438;&#x043B;&#x043E;&#x0436;&#x0435;&#x043D;&#x0438;&#x044F; &#x0432; &#x044D;&#x0442;&#x043E;&#x043C; &#x0444;&#x043E;&#x0440;&#x0443;&#x043C;&#x0435;<br />&#x0412;&#x044B; <b>&#x043C;&#x043E;&#x0436;&#x0435;&#x0442;&#x0435;</b> &#x0441;&#x043A;&#x0430;&#x0447;&#x0438;&#x0432;&#x0430;&#x0442;&#x044C; &#x0444;&#x0430;&#x0439;&#x043B;&#x044B; &#x0432; &#x044D;&#x0442;&#x043E;&#x043C; &#x0444;&#x043E;&#x0440;&#x0443;&#x043C;&#x0435;<br />

Это всего-навсего вот этот текст:
Код: Выделить всё
Вы можете добавлять приложения в этом форуме
Вы можете скачивать файлы в этом форуме

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 18.02.2006 (Сб) 13:12

Какие из именованных ентитей планируется обрабатывать? (есть список?)
Изображение

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 18.02.2006 (Сб) 13:16

Желательно все, т.к. для ограниченного набора у меня есть решение.
Посмотреть их можно здесь. Не знаю все ли там, но много. Там в последних строках даже не известны коды для символов. Т.е. стандарт ещё не стандарт?

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 18.02.2006 (Сб) 13:21

А то, что большую часть перечисленных ентитей даже IE6 не распознаёт -- тебя не смущает?
По-моему, это какой-то сильно левый список: кому-то было здорово нечего делать, и он напридумывал имена для наугад выбранной тысячи символов.
Изображение

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 18.02.2006 (Сб) 13:26

IE не единственный на планете, хоть и оч. популярный. Кроме того если такая API есть, то пусть у неё голова болит что и как конвертировать, потому и ищу её :).

Если же своё решение, то хотябы в рамках ISOnum и ISOlat1.

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 18.02.2006 (Сб) 13:38

Я уверен, что такой API нету, и пытаюсь сейчас написать кое-что своё.
Изображение

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 18.02.2006 (Сб) 14:20

Держи код, гыгыгы.

Код: Выделить всё
Option Explicit

Private Sub Main()
    MsgBox Decode("&ldquo;&#x43;&oslash;ø&#x142;&rdquo;&mdash;хак")
End Sub


Public Function Decode(HTML As String) As String
    Dim o As Object: Set o = CreateObject("MSXML.DOMDocument")
    o.loadXML "<!DOCTYPE HTML PUBLIC ""-//////"" ""http://users.isnet.ru/tyomitch/htmlent.dtd""><HTML>" + HTML + "</HTML>"
    Decode = o.selectSingleNode("/HTML").Text
End Function
Изображение

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 18.02.2006 (Сб) 14:44

Круто!!! Супер-пупер!!! Практически API'шка :) и универсально.

Этот код надо в рамочку взять и прибить на доску почёта. :)

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 18.02.2006 (Сб) 15:04

Блин, рано обрадовался. Этот код имеет побочный эффект (что не умаляет его достоинств) - если entity не описан в приведённых схемах или используется спецсимвол, например амперсант, то XML-документ читается с ошибкой и никакой конвертации не происходит :(. А добиться такой ситуации проще простого, достаточно ввести уже выше упомянутый амперсант или символы больше/меньше. Кроме того, при конвертации пропадают ведущие и замыкающие пробелы.

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 18.02.2006 (Сб) 15:37

А так?

Код: Выделить всё
Public Function Decode(s As String) As String
  Dim d As Object
 
  Set d = New HTMLDocument
   
  d.write "<html><body><pre>" & s & "</pre></body></html>"
 
  Do While d.body Is Nothing
    'DoEvents
  Loop
 
  Do Until StrComp(d.body.readyState, "complete", vbTextCompare) = 0
    'DoEvents
  Loop
 
  Decode = d.body.innerText
End Function
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 18.02.2006 (Сб) 16:00

GSerg писал(а):А так?

Я примерно об этом и думал :). Тот самый путь. Он работает более стабильно, но имеет тоже один маленький нюанс: если XML строго регламентирован, то HTML как раз не очень, и вместо того чтобы игнорировать неправильные entity он их пытается отобразить. Если написать &uumlaut;, то вместо &uumlaut; (т.к. это не существующий entity, а просто текст) он отобразит üaut;, т.е. он самостоятельно подставил точку с запятой туда где её нет и не должно было быть. Но этот трабл существенно мягче, чем у tyomitch'а, т.к. можно оговорить особенности написания слов с амперсандами, если надо чтобы амперсант отображался как символ, с пользователем.

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 28.04.2007 (Сб) 12:21

Это не вопрос, а просто заметки на полях. Может кому пригодится и мне легче искать.

С проблемами кодировок сталкивался практически каждый. Особенно программирующие для веба где, в отличие от настольных программ, невозможно заранее предсказать языковой состав аудитории. До недавнего времени при создании сайта я выбирал основной кодировкой windows-1251, т.к. аудитория в основном русскоговорящая. Все символы из других кодировок полученные как entities приходилось конвертировать в unicode для записи в БД и обратно для правильного отображения. Этот топик как раз и решал задачу конвертирования. Постоянно возникающая проблема -- амперсанд. Как его правильно интерпретировать? Кроме того entities могут быть как численные так и именованые. Именованых много и список может расширятся дальше.

Потому необходимо универсальное решение. Такое решение, очень близкое к идеальному, предложил чуть выше GSerg, но не всегда возможно использовать собственные компоненты. Потому назрели предпосылки для революции. Перехожу на UTF-8. Современные редакторы прекрасно понимают эту кодировку (иногда даже слишком хорошо -- бывает нужно посмотреть на кракозябли, а такой возможности нет). Проблемы с entities и амперсандом решаются сразу и навсегда, хранить можно что угодно. Есть, правда, пара минусов: увеличение кода страницы и необходимость конвертирования в unicode и обратно. Первый недостаток слихвой компенсируется универсальностью, второй же неустраним при любом раскладе, но, в отличие от конвертера entities, алгоритм конвертирования в/из UTF-8 однозначен и не зависит от возможного будущего расширения диапазона символов. Кроме того, легко реализуется без привлечения дополнительных средств.

Код: Выделить всё
Unicode UTF-8
0x00000000 — 0x0000007F: 0xxxxxxx
0x00000080 — 0x000007FF: 110xxxxx 10xxxxxx
0x00000800 — 0x0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
0x00010000 — 0x001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
(теоретически возможны, но не включены в стандарт также:)
0x00200000 — 0x03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
0x04000000 — 0x7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx


Код: Выделить всё
Function EncodeUTF8(ByVal sInput) 'As String

    Dim iCharPos, iCharCode
    Dim iLoByteCounter, iLoByteCount, iHiBytePrefix

    Dim iInputLen: iInputLen = Len(sInput)
    ReDim aUTF8(iInputLen)

    For iCharPos = 1 To iInputLen

        aUTF8(iCharPos) = Mid(sInput, iCharPos, 1)
        iCharCode = AscW(aUTF8(iCharPos))

        If (iCharCode > &h7F) Then '0xxx xxxx

            If (iCharCode < &h800) Then
                iHiBytePrefix = 192 '110xxxxx prefix for 2 bytes unicode
                iLoByteCount = 1
            ElseIf (iCharCode < &h10000) Then
                iHiBytePrefix = 224 '1110xxxx prefix for 3 bytes unicode
                iLoByteCount = 2
            ElseIf (iCharCode < &h200000) Then
                iHiBytePrefix = 240 '11110xxx prefix for 4 bytes unicode
                iLoByteCount = 3
            ElseIf (iCharCode < &h4000000) Then
                iHiBytePrefix = 248 '111110xx prefix for 5 bytes unicode
                iLoByteCount = 4
            Else
                iHiBytePrefix = 252 '1111110x prefix for 6 bytes unicode
                iLoByteCount = 5
            End If

            aUTF8(iCharPos) = ""
            For iLoByteCounter = iLoByteCount To 1 Step -1
                '6 младших битов от iCharCode + префикс 10xxxxxx
                aUTF8(iCharPos) = Chr(128 Or iCharCode And 63) & aUTF8(iCharPos)
                iCharCode = iCharCode \ 64 'сдвиг на 6 битов вправо
            Next
            aUTF8(iCharPos) = Chr(iHiBytePrefix Or iCharCode) & aUTF8(iCharPos)

        End If
    Next
    EncodeUTF8 = Join(aUTF8, "")

End Function


Код: Выделить всё
Function DecodeUTF8(ByVal sInput) 'As String

    Dim iCharPos, iCharCode
    Dim iLoByteCounter, iLoByteCount, iLoCharCode

    Dim iInputLen: iInputLen = Len(sInput)
    ReDim aUnicode(iInputLen)

    For iCharPos = 1 To iInputLen

        aUnicode(iCharPos) = Mid(sInput, iCharPos, 1)
        iCharCode = Asc(aUnicode(iCharPos))

        If (iCharCode > 191) Then

            If (iCharCode < 224) Then '110xxxxx prefix for 2 bytes unicode
                iCharCode = iCharCode And 31 'remove the 3 bit two bytes prefix
                iLoByteCount = 1
            ElseIf (iCharCode < 240) Then '1110xxxx prefix for 3 bytes unicode
                iCharCode = iCharCode And 15 'remove the 4 bit three bytes prefix
                iLoByteCount = 2
            ElseIf (iCharCode < 248) Then '11110xxx prefix for 4 bytes unicode
                iCharCode = iCharCode And 7 'remove the 5 bit four bytes prefix
                iLoByteCount = 3
            ElseIf (iCharCode < 252) Then '111110xx prefix for 5 bytes unicode
                iCharCode = iCharCode And 3 'remove the 6 bit five bytes prefix
                iLoByteCount = 4
            Else '1111110x prefix for 6 bytes unicode
                iCharCode = iCharCode And 1 'remove the 7 bit six bytes prefix
                iLoByteCount = 5
            End If

            For iLoByteCounter = 1 To iLoByteCount
                iLoCharCode = Asc(Mid(sInput, iCharPos + iLoByteCounter, 1)) 'the next byte
                'сдвиг влево на 6 битов + 6 младших битов следующего символа
                iCharCode = iCharCode * 64 + (iLoCharCode And 63)
            Next

            aUnicode(iCharPos) = ChrW(iCharCode)
            iCharPos = iCharPos + iLoByteCount

        End If
    Next
    DecodeUTF8 = Join(aUnicode, "")

End Function


Вернуться в ASP и VBScript

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 12

    TopList