Rody66 писал(а):Вот результат в моей интерпретации:
Твоя интерпретация — образец дрянейшей интерпретации. Ты взял и выкинул из моего кода все самые хорошие и добрые моменты и заменил полной гадостью.
У меня аргумент был ByRef, ты его заменил на ByVal. Ты отдаёшь себя, черт возьми, отчёт, что ты заменил
хорошее на
плохое? Ты отдаёшь себе отчёт, что ты заменил отсутствие ненужного копирования большой строки на наличие ненужного копирования большой строки?
Ты заменил хорошее имя
sInput, в котором 1/6 часть была посвящена техническому типу, и 5/6 — логической сути, на глупое имя
inString, в котором не видно сути.
Ты заменил правильную проверку на пустоту строки
If Len(sInput) = 0 на неправильную проверку на пустоту строки
If inString = "".
Ты занил более само-документирующую
Space на менее само-документирующую
String, но это мелочь.
Ты заменил 4-ый аргумент функции MultiByteToWideChar на
-1, что делать
категорически недопустимо Этим ты внёс в свою программу баг, из-за которого все строки, содержащие где-нибудь в середине или начале символ с кодом 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 (19.18 Кб) Просмотров: 3690
(кегль шрифта специально увеличен)
Исходник: