MS Inernet Transfer Control - как получить символы кирилицы?

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
Rody66
Продвинутый пользователь
Продвинутый пользователь
 
Сообщения: 183
Зарегистрирован: 16.01.2011 (Вс) 17:03

MS Inernet Transfer Control - как получить символы кирилицы?

Сообщение Rody66 » 17.06.2012 (Вс) 1:02

Доброго дня.
Не могу найти способ получить нормальные русские символы в исходнике страницы. Пример: s=Inet.OpenURL("http://ya.ru") вместо русских символов в содержимом s будет какая-то ересь.
Кстати если эту ересь перекинуть в Notepad++ и выбрать кодировку UTF-8, то она превращается в нормальные русские символы. Из чего делаю вывод, что страница грузится в кодировке UTF=8. А это, насколько мне известно, юникод. Но вот загвоздка.. s=StrConv(s, vbFromUnicode) тоже работает не так как нужно, и ничего хорошего мы не получаем. Что же не так? И как все-таки эти русские символы получить?
Пример русских символов: Сортировать
Спасибо.

iGrok
Артефакт VBStreets
Артефакт VBStreets
 
Сообщения: 4272
Зарегистрирован: 10.05.2007 (Чт) 16:11
Откуда: Сетевое сознание

Re: MS Inernet Transfer Control - как получить символы кирил

Сообщение iGrok » 17.06.2012 (Вс) 2:01

Rody66 писал(а):А это, насколько мне известно, юникод.

Вот тут и кроется источник проблем. Юникод, да не тот.

Читать сюда.
label:
cli
jmp label

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: MS Inernet Transfer Control - как получить символы кирил

Сообщение Хакер » 17.06.2012 (Вс) 3:00

Rody66 писал(а):И как все-таки эти русские символы получить?

Конвертировать из UTF-8 в UCS-2. StrConv этого не умеет только MultiByteToWideChar.
Предварительно прочитав (пять раз) статью, ссылка на которую дана выше.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

parserdcc
Начинающий
Начинающий
 
Сообщения: 10
Зарегистрирован: 17.10.2009 (Сб) 7:05

Re: MS Inernet Transfer Control - как получить символы кирил

Сообщение parserdcc » 17.06.2012 (Вс) 8:05

Код: Выделить всё
Public Function UTF8_16(UTF8Data$)
    UTF8_16 = ""
    Dim i$, j$, j2$, ch, k1$, k2$, k3$, m$
    i = 1
    Do While i <= Len(UTF8Data)
        ch = Mid(UTF8Data, i, 1)
        j = CLng(Asc(ch))
        If j >= 128 Then
            If j < 224 Then
                k1 = j Mod 32
                i = i + 1
                ch = Mid(UTF8Data, i, 1)
                j2 = CLng(Asc(ch))
                k2 = j2 Mod 64
                UTF8_16 = UTF8_16 & ChrW(k2 + k1 * 64)
            Else
                k1 = j Mod 16
                i = i + 1
                ch = Mid(UTF8Data, i, 1)
                j2 = CLng(Asc(ch))
                k2 = j2 Mod 64
                i = i + 1
                ch = Mid(UTF8Data, i, 1)
                j2 = CLng(Asc(ch))
                k3 = j2 Mod 64
                UTF8_16 = UTF8_16 & ChrW(k3 + (k2 + k1 * 64) * 64)
            End If
        Else
            UTF8_16 = UTF8_16 & ch
        End If
        i = i + 1
    Loop
End Function


На выходе функции будет русский язык.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: MS Inernet Transfer Control - как получить символы кирил

Сообщение Хакер » 17.06.2012 (Вс) 8:07

Отвратительный код, никому больше его не показывай.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Rody66
Продвинутый пользователь
Продвинутый пользователь
 
Сообщения: 183
Зарегистрирован: 16.01.2011 (Вс) 17:03

Re: MS Inernet Transfer Control - как получить символы кирил

Сообщение Rody66 » 17.06.2012 (Вс) 13:51

Искал по форуму по MultiByteToWideChar, наткнулся на пост arthur2, немного укорочил его код, всё отлично работает. Всем большое спасибо.
Код: Выделить всё
Private Declare Function MultiByteToWideChar Lib "kernel32.dll" (ByVal CodePage As Long, ByVal dwFlags As Long, ByVal lpMultiByteStr As String, ByVal cchMultiByte As Long, ByVal lpWideCharStr As Long, ByVal cchWideChar As Long) As Long
Private Declare Function WideCharToMultiByte Lib "kernel32.dll" (ByVal CodePage As Long, ByVal dwFlags As Long, ByVal lpWideCharStr As Long, ByVal cchWideChar As Long, ByVal lpMultiByteStr As Long, ByVal cchMultiByte As Long, ByVal lpDefaultChar As Long, ByVal lpUsedDefaultChar As Long) As Long

Public Function UTF8ToWin(ByVal inString As String) As String
        Dim hMemLock1   As Long, hMemLock2  As Long
        Dim iStrSize    As Long, lMaxSize As Long, str1 As String, str2 As String
        inString = inString & vbNullChar
        lMaxSize = Len(inString)
        str1 = String$(lMaxSize, 0&)
        str2 = String$(lMaxSize, 0&)
        hMemLock1 = StrPtr(str1)
        hMemLock2 = StrPtr(str2)
        iStrSize = MultiByteToWideChar(CP_UTF8, 0&, inString, &HFFFF, hMemLock1, lMaxSize)
        iStrSize = WideCharToMultiByte(0&, 0&, hMemLock1, &HFFFF, hMemLock2, iStrSize, 0&, 0&)
        If Len(iStrSize) Then UTF8ToWin = StrConv(str2, vbUnicode)
End Function

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: MS Inernet Transfer Control - как получить символы кирил

Сообщение Хакер » 17.06.2012 (Вс) 15:19

Адовая ересь. Авторов такого кода надо расстреливать.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: MS Inernet Transfer Control - как получить символы кирил

Сообщение Хакер » 17.06.2012 (Вс) 15:52

Это надо быть полным кретином, чтобы имея задачу «преобразовать UTF-8 в UCS-2» делать преобразование:
UTF-8UCS-2ANSIUCS-2
теряя при этом безвозвратно 99 процентов символов текста, вместо того, чтобы сделать просто
UTF-8UCS-2

Правильный код для варианта с API-функциями:
Код: Выделить всё
Private Declare Function MultiByteToWideChar Lib "kernel32" (ByVal CodePage As Long, ByVal dwFlags As Long, lpMultiByteStr As Any, ByVal cchMultiByte As Long, lpWideCharStr As Any, ByVal cchWideChar As Long) As Long
Private Const CP_UTF8 = 65001
Public Function Utf8ToUcs2(ByRef sInput As String) As String
    Dim ret As Long
    If Len(sInput) = 0 Then Exit Function Else Utf8ToUcs2 = Space(Len(sInput))
    ret = MultiByteToWideChar(CP_UTF8, 0, _
                              ByVal StrPtr(sInput), Len(sInput), _
                              ByVal StrPtr(Utf8ToUcs2), LenB(Utf8ToUcs2))
    If ret = 0 Then Error 51 Else Utf8ToUcs2 = Left$(Utf8ToUcs2, ret)
End Function


А ты Rody, просто бессовестный. Ты гарантированно не прочитал статью (пять раз), и даже не поинтересовался, годен ли тот код, который ты отрыл в каком-то мусорном баке. Считаешь себя достаточно грамотным, чтобы определять, хорош ли код? Или тебе вообще наплевать абсолютно на всё, лишь бы абы-абы-абы-как работало?
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: MS Inernet Transfer Control - как получить символы кирил

Сообщение arthur2 » 17.06.2012 (Вс) 19:27

Rody66 писал(а):наткнулся на пост arthur2, немного укорочил его код,
Ну, это не мой код. Это моя тогдашняя (в 2008) попытка на ощупь исправить жуткие косяки чужого кода, не вполне понимая его смысл. "Укоротил", это, я так понимаю, выбросил закомментированные куски того, на что как раз укоротил оригинальный код я :)

Именно мой код для подобной задачи, уже с пониманием смысла, здесь: viewtopic.php?p=6736460#p6736460 Как можно заметить, практически то же самое, что у Хакера - так что прошу меня не расстреливать :)
Артур
 
   

Rody66
Продвинутый пользователь
Продвинутый пользователь
 
Сообщения: 183
Зарегистрирован: 16.01.2011 (Вс) 17:03

Re: MS Inernet Transfer Control - как получить символы кирил

Сообщение Rody66 » 18.06.2012 (Пн) 0:18

Это надо быть полным кретином, чтобы имея задачу «преобразовать UTF-8 в UCS-2» делать преобразование:
— UTF-8 → UCS-2 → ANSI → UCS-2
теряя при этом безвозвратно 99 процентов символов текста

Я об этом думал, но т. к. код вполне себе неплохо работал, счел необязательным что-то оптимизировать.
А насчет потери не понял. У меня ничего не терялось.
А ты Rody, просто бессовестный. Ты гарантированно не прочитал статью (пять раз), и даже не поинтересовался, годен ли тот код, который ты отрыл в каком-то мусорном баке. Считаешь себя достаточно грамотным, чтобы определять, хорош ли код? Или тебе вообще наплевать абсолютно на всё, лишь бы абы-абы-абы-как работало?

Да, ты прав, прочел всего один раз (кстати, по факту уже 2, ибо недавно ты тоже мне ее предлагал).
Нет, особо грамотным себя не считаю. Насчет абы-абы - код работал и всё устраивало (кроме того, что так и не приложил достаточно усилий, чтобы осмыслить его полностью), поэтому и повода искать что-то иное не было, темболее, учитывая то, что на поиски Я достаточно немало времени.
arthur2, спасибо за линк, почитал твои посты, и все-таки в полной мере разобрался с параметрами. Правда, вот что Я не очень понял: у ф-ции параметров 6, а тут ты описываешь целых 8, откуда еще 2? - viewtopic.php?p=6736460#p6736467
Хакер, твой код почему то работает неверно, и на выходе кракозябры. А вот код Артура отлично работает.
Вот результат в моей интерпретации:
Код: Выделить всё
Public Const CP_UTF8 = 65001
Private Declare Function MultiByteToWideChar Lib "kernel32.dll" (ByVal CodePage As Long, ByVal dwFlags As Long, ByVal lpMultiByteStr As String, ByVal cchMultiByte As Long, ByVal lpWideCharStr As Long, ByVal cchWideChar As Long) As Long
Public Function Utf8ToUcs2(ByVal inString As String) As String
    Dim ret As Long, StringSize As Long, strBuffer As String
    If inString = "" Then Exit Function
    StringSize = Len(inString)
    strBuffer = String$(StringSize, 0&)
    ret = MultiByteToWideChar(CP_UTF8, 0&, inString, -1&, StrPtr(strBuffer), StringSize)
    If ret >= 0 Then Utf8ToUcs2 = Left$(strBuffer, StringSize - 1)
End Function

И последнее, не сочтите за идиотизм, но UCS2 - это же UTF-16 ?

iGrok
Артефакт VBStreets
Артефакт VBStreets
 
Сообщения: 4272
Зарегистрирован: 10.05.2007 (Чт) 16:11
Откуда: Сетевое сознание

Re: MS Inernet Transfer Control - как получить символы кирил

Сообщение iGrok » 18.06.2012 (Пн) 0:58

Rody66 писал(а):но UCS2 - это же UTF-16

Не совсем, и у Джоэла этот момент таки не описан.
UCS2 - это первоначальный стандарт, с пространством в 65536 символов.
UTF-16 появился позже, и в нём введены "суррогатные пары" - возможность представления одного символа парой кодовых точек. Таким образом пространство расширено до 1 112 064 символов, в википедии этот момент описан, если интересно. Ну или вот тут чётко несколько строк про различия между ними: http://www.unicode.org/faq/basic_q.html#14
label:
cli
jmp label

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: MS Inernet Transfer Control - как получить символы кирил

Сообщение Хакер » 18.06.2012 (Пн) 9:18

Rody66 писал(а):Вот результат в моей интерпретации:

Твоя интерпретация — образец дрянейшей интерпретации. Ты взял и выкинул из моего кода все самые хорошие и добрые моменты и заменил полной гадостью.

У меня аргумент был ByRef, ты его заменил на ByVal. Ты отдаёшь себя, черт возьми, отчёт, что ты заменил хорошее на плохое? Ты отдаёшь себе отчёт, что ты заменил отсутствие ненужного копирования большой строки на наличие ненужного копирования большой строки?

Ты заменил хорошее имя sInput, в котором 1/6 часть была посвящена техническому типу, и 5/6 — логической сути, на глупое имя inString, в котором не видно сути.

Ты заменил правильную проверку на пустоту строки If Len(sInput) = 0 на неправильную проверку на пустоту строки If inString = "".

Ты занил более само-документирующую Space на менее само-документирующую String, но это мелочь.

Ты заменил 4-ый аргумент функции MultiByteToWideChar на -1, что делать категорически недопустимо :twisted: Этим ты внёс в свою программу баг, из-за которого все строки, содержащие где-нибудь в середине или начале символ с кодом 0 будет автоматически урезаться до этого символа. Ты мог написать StringSize, но написал -1. Не было никакой сложности написать StringSize, но ты взял и написал -1. Что у тебя в голове?

Ты убрал из функции проверку ошибок. У тебя возврат функцией нулевого значение считается нормальным сценарием действия. Любая хоть чуть-чуть профессиональная программа на 10 % состоит из кода, осуществляющего полезные действия, и на 90 % — из кода обработки ошибок, могущих возникнуть в процессе этих действий. Но ты всё это убрал. У тебя по твоей отвратительной логике, заложенной в код, функция WideCharToMultiByte может вернуть ноль, хотя в реальной жизни она не может, потому что она вернут 0 только для пустой входной строки, но если входная строка пуста, то дело до вызова функции WideCharToMultiByte не дойдёт, потому что у тебя до её вызова стоит проверяющее пустоту условие. Поэтому ноль — однозначное свидетельство ошибки. Но у тебя это допустимый и правильный ход работы.

Rody66 писал(а):Я об этом думал, но т. к. код вполне себе неплохо работал, счел необязательным что-то оптимизировать.

Нет такого понятия в инженерном деле как «вполне себе». Летай пожалуйста, на самолётах, которые «вполне себе» летают, по мнению конструктора.

Есть понятие «соответствуют предъявляемым требованиям» и есть понятия «не соответствует». В твоём случае трабования такие: она должна без искажений данных конвертировать UTF8-представление строки в UCS2-представление строки. Реальность такова, что для 99 % входных символов твоя функция исказит данные. Но ты имел невероятную глупость проверить функцию на оставшемся 1 % вариантов входных символов. В оставшийся 1 % входят спецсимволы, латинские символы, цифры и символы текущей системной локали (для твоего компьютера — предположительно «русской» локали). Всё. Ты обидел украинцев, белорусов, казахов, немцев, евреев, арабов, и ещё всех нормальных совестливых программистов. Своей наивной зашоренной позиций, что кроме латинских и русских букв в мире не существует никаких других.

Rody66 писал(а):Хакер, твой код почему то работает неверно, и на выходе кракозябры.

Признаю, в ней есть ошибки, я писал её прямо здесь в форме постинга, без проверок.

А причина подобных ошибок проста. Идеологически запрещено хранить UTF8-строку (или UTF7-строку или любую другую) в переменной типа String. Потому что существует как минимум два способа хранить UTF8-строку внтри String-переменной, и не существует абсолютно никакого способа узнать, какой из них используется, не существует никакого способа пометить переменную как использующую какой-то конкретный способ. Не существует способа заставить инструмент проконтролировать, что использован правильный способ. А главная цель использования любого программистского инструмента, такого как язык и компилятор — не упрощение работы программиста, а ужесточение контроля за программистом воимя избеждания типичных для программиста (как для человека) ошибок.

Так вот, UTF8 строка, лежащая внутри String переменной, может лежать либо как есть: каждый байт UTF8-строки совпадает с каждым байтом String-переменной, либо в по-глупому-в-юнкод-преобразованном виде, каждый каждый символ бессмысленной UCS-2 строки совпадает по своему коду со значением каждого байта UTF8-строки.

Вот у тебя судя по всему используется второй способ. Единственная идеологически правильная форма хранения UTF8-текста: хранение в массиве байтов. Без всяких «но».

Соответственно, три варианта функции.

Для случая, когда UTF8-строка представляет (как положено) в виде массива байтов.
Код: Выделить всё
Public Function Utf8ToUcs2(ByRef sInputUtf8Str() As Byte) As String
    Dim ret As Long
    Dim nInpLength As Long: nInpLength = ByteArySize(sInputUtf8Str)
    If nInpLength = 0 Then Exit Function Else Utf8ToUcs2 = Space(nInpLength)
    ret = MultiByteToWideChar(CP_UTF8, 0, _
                              sInputUtf8Str(LBound(sInputUtf8Str)), nInpLength, _
                              ByVal StrPtr(Utf8ToUcs2), nInpLength)
    If ret = 0 Then Error 51 Else Utf8ToUcs2 = Left$(Utf8ToUcs2, ret)
End Function


Для случая, когда UTF8-строка (как не следует делать) засунута в String-переменную в том виде, в каком есть.
Код: Выделить всё
Public Function Utf8AsIsToUcs2(ByRef sAsIsBytes As String) As String
    Dim ret As Long
    Dim nInpLength As Long: nInpLength = LenB(sAsIsBytes)
    If nInpLength = 0 Then Exit Function Else Utf8AsIsToUcs2 = Space(nInpLength)
    ret = MultiByteToWideChar(CP_UTF8, 0, _
                              ByVal StrPtr(sAsIsBytes), nInpLength, _
                              ByVal StrPtr(Utf8AsIsToUcs2), nInpLength)
    If ret = 0 Then Error 51 Else Utf8AsIsToUcs2 = Left$(Utf8AsIsToUcs2, ret)
End Function


Для самого тупого случая (как, надо полагать, у тебя), когда UTF8-строка хранится в String-переменной, причём каждому байту UTF8-строки соответствует двухбайтная пара String-переменная, представляющая UCS2-символ, код которого равен значение соответствующего байта оригинальной UTF8-строки.
Код: Выделить всё
Public Function Utf8DirtyToUcs2(ByVal sDirtyString As String) As String
    Dim ret As Long
    Dim nInpLength As Long: nInpLength = Len(sDirtyString)
    If nInpLength = 0 Then Exit Function Else Utf8DirtyToUcs2 = Space(nInpLength)
    sDirtyString = StrConv(sDirtyString, vbFromUnicode)
    ret = MultiByteToWideChar(CP_UTF8, 0, _
                              ByVal StrPtr(sDirtyString), nInpLength, _
                              ByVal StrPtr(Utf8DirtyToUcs2), nInpLength)
    If ret = 0 Then Error 51 Else Utf8DirtyToUcs2 = Left$(Utf8DirtyToUcs2, ret)
End Function


Ну и чтобы не было лишних вопросов насчёт ByteArySize:
Код: Выделить всё
Private Function ByteArySize(ByRef b() As Byte) As Long
    On Error Resume Next
    ByteArySize = UBound(b) - LBound(b) + 1
End Function


И вот проверка этих трёх функций.
Задача, сконвертировать фразу
Hello, Вселенная, نهار, Straße, φανός, дәріхана!!
которая содержит слова на английском, русском, арабском («день»), немецком («улица»), греческом («фонарь») и казахском («аптека») языках, хранимую в формате UTF-8, в формат UCS-2, и вывести с помощью MessageBox на экран. Конвертация производится всеми тремя функциями подряд. Продемонстрированны все три варианта в порядке возрастания степени их отстойности:
utf8_to_ucs2_result.png
utf8_to_ucs2_result.png (19.18 Кб) Просмотров: 3690

(кегль шрифта специально увеличен)

Исходник:
shame_on_rody66.zip
Позор Rody66
(2.43 Кб) Скачиваний: 132
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: MS Inernet Transfer Control - как получить символы кирил

Сообщение ger_kar » 19.06.2012 (Вт) 18:26

Хакер писал(а):Ты занил более само-документирующую Space на менее само-документирующую String, но это мелочь.
Я тоже всегда применяю String, ибо считаю, что это более правильно, так как например при вызовах WinApi из Си например передается указатель на текстовый буфер, который в пустом состоянии содержит нули. Нафига его пробелами то забивать? И что это такое само-документирующуя функция, я что-то вообще не въехал, как функция может документировать сама себя?
Бороться и искать, найти и перепрятать

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: MS Inernet Transfer Control - как получить символы кирил

Сообщение Хакер » 19.06.2012 (Вт) 19:08

ger_kar писал(а):так как например при вызовах WinApi из Си например передается указатель на текстовый буфер, который в пустом состоянии содержит нули.

Какая разница, чем заполнен буфер, если он является буфером-приёмником, а не буфером-источником данных?
ger_kar писал(а):
И что это такое само-документирующуя функция, я что-то вообще не въехал, как функция может документировать сама себя?

Код может самодокументировать себя. Ещё бы ты не въехал, если ты английского не знаешь нифига.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: MS Inernet Transfer Control - как получить символы кирил

Сообщение ger_kar » 19.06.2012 (Вт) 19:11

Хакер писал(а):Код может самодокументировать себя. Ещё бы ты не въехал, если ты английского не знаешь нифига.
Если будет нетрудно, поведай на досуге, что это за фишка такая.
Бороться и искать, найти и перепрятать


Вернуться в Visual Basic 1–6

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

Сейчас этот форум просматривают: Google-бот и гости: 2

    TopList