Есть сервер под Linux. Есть клиент под винду на C#.
С сервера передаются строки в utf8. Тип данных wchar_t, длиной 4 байта. Клиенту они передаются тоже по 4 байта на символ.
На клиенте принимается строка и переводится в Encoding.Unicode через Encoding.UTF8.GetString().
Проблема:
Т.к. utf8 не имеет жесткого размера, а сервер присылает строку с жестким количеством байт на символ, то появляется бага.
Вместо строчки:
['H', 'e', 'l', 'l', 'o'] получаем:
['H', 0, 0, 0, 'e', 0, 0, 0, 'l', 0, 0, 0, 'l', 0, 0, 0, 'o', 0, 0, 0]
Т.е. на каждый распознанный конвертером символ получаем дополнительно 3 нуля. Фактически символ "умещался" в один байт, а сервер прислал 4 байта.
Как лучше избавиться от такого косяка?.
Сейчас клиент врукопашную удаляет ненужные нули. Но тогда при передаче серверу нужно будет "наращивать" нули. И это всё кажется жутко криво.
Есть еще вариант использовать на сервере iconv, но он(iconv) на сервере почему то падает.
Здравствуйте, neFormal, Вы писали:
F>Есть сервер под Linux. Есть клиент под винду на C#. F>С сервера передаются строки в utf8. Тип данных wchar_t, длиной 4 байта. Клиенту они передаются тоже по 4 байта на символ. F>На клиенте принимается строка и переводится в Encoding.Unicode через Encoding.UTF8.GetString().
F>Проблема: F>Т.к. utf8 не имеет жесткого размера, а сервер присылает строку с жестким количеством байт на символ, то появляется бага. F>Вместо строчки: F>['H', 'e', 'l', 'l', 'o'] получаем: F>['H', 0, 0, 0, 'e', 0, 0, 0, 'l', 0, 0, 0, 'l', 0, 0, 0, 'o', 0, 0, 0] F>Т.е. на каждый распознанный конвертером символ получаем дополнительно 3 нуля. Фактически символ "умещался" в один байт, а сервер прислал 4 байта.
F>Как лучше избавиться от такого косяка?.
F>Сейчас клиент врукопашную удаляет ненужные нули. Но тогда при передаче серверу нужно будет "наращивать" нули. И это всё кажется жутко криво. F>Есть еще вариант использовать на сервере iconv, но он(iconv) на сервере почему то падает.
Это похоже на кодировку utf-32, может, нужно использовать её?
Здравствуйте, vmpire, Вы писали:
V>Это похоже на кодировку utf-32, может, нужно использовать её?
Честно говоря, не знаю о совместимости utf8 и utf32, возможно utf8 — это аналог utf32 с плавающим размером
Попробуем.
Но мне кажется логичным данное поведение для utf8, т.к. размер у него не жестко заданный, а в плюсовом коде нужно размер знать заранее.
И копипаста из вики, которая меня натолкнула на эту мысль:
Остальные символы Юникода изображаются последовательностями длиной от 2 до 6 байтов (реально только до 4 байт, поскольку использование кодов больше 221 не планируется), в которых первый байт всегда имеет вид 11xxxxxx, а остальные — 10xxxxxx.
Здравствуйте, neFormal, Вы писали:
F>Здравствуйте, vmpire, Вы писали:
V>>Это похоже на кодировку utf-32, может, нужно использовать её?
F>Честно говоря, не знаю о совместимости utf8 и utf32, возможно utf8 — это аналог utf32 с плавающим размером F>Попробуем.
F>Но мне кажется логичным данное поведение для utf8, т.к. размер у него не жестко заданный, а в плюсовом коде нужно размер знать заранее. F>И копипаста из вики, которая меня натолкнула на эту мысль: F>
F>Остальные символы Юникода изображаются последовательностями длиной от 2 до 6 байтов (реально только до 4 байт, поскольку использование кодов больше 221 не планируется), в которых первый байт всегда имеет вид 11xxxxxx, а остальные — 10xxxxxx.
utf-8, utf-16, utf-32, ucs-2... это формы представления символов Unicode, которые сами по себе занимают по 4 байта каждый.
uft-8 и utf-16 — кодировки переменной длины (utf-8 от 1 до 6 байтов, utf-16 — 2 или 4 байта)
utf-32 и ucs-4 — кодировки с фиксированным количеством байт (4 штуки)
В .NET есть встроенная кодировка uft-32, про которую я и говорю
Здравствуйте, neFormal, Вы писали:
F>Есть сервер под Linux. Есть клиент под винду на C#. F>С сервера передаются строки в utf8. Тип данных wchar_t, длиной 4 байта.
Этого не может быть. Два утверждения противоречат друг другу. В UTF-8 используется переменное количество байт на символ; в частности, вся латиница умещается в 1 байт на символ.
Поэтому нужно выяснить, в какой кодировке передаются строки с сервера на самом деле. Как уже верно предположили, это может быть UTF32.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, vmpire, Вы писали:
V>utf-8, utf-16, utf-32, ucs-2... это формы представления символов Unicode, которые сами по себе занимают по 4 байта каждый.
Это чрезмерно упрощенное представление. Сode points Unicode не занимают никакого количества байт; это натуральные числа. Символ некоего алфавита не всегда имеет однозначное представление в виде code points, в частности, буква ё может быть представлена одним code point либо двумя (кириллическая е + две точки над ней).
Любая кодировка (в том числе и utf-32) задает правила конверсии между байтовой последовательностью и цепочкой натуральных чисел.
Таким образом, в зависимости от кодировки, та же буква ё может занимать от 1 до 8 байт.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
F>>Есть сервер под Linux. Есть клиент под винду на C#. F>>С сервера передаются строки в utf8. Тип данных wchar_t, длиной 4 байта. S>Этого не может быть. Два утверждения противоречат друг другу. В UTF-8 используется переменное количество байт на символ; в частности, вся латиница умещается в 1 байт на символ.
Поэтому в линухе используется, видимо, количество байт "с запасом", чтобы все используемые символы наверняка влезли.
Вот кусок кода оттуда (stddef.h):
#ifndef __WCHAR_TYPE__
#define __WCHAR_TYPE__ int// neFormal: вот эти вот 4 байта#endif
#ifndef __cplusplus
typedef __WCHAR_TYPE__ wchar_t;
#endif
Для сравнения в винде используется utf16le и 2 байта на символ и:
typedef unsigned short wchar_t; // neFormal: вот эти 2 байта
S>Поэтому нужно выяснить, в какой кодировке передаются строки с сервера на самом деле. Как уже верно предположили, это может быть UTF32.
Проверил, не utf32.
Коды символов, переданные по сети такие же, как если бы писать utf8 в файл. Разница только в дополнительных байтах.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, vmpire, Вы писали:
V>>utf-8, utf-16, utf-32, ucs-2... это формы представления символов Unicode, которые сами по себе занимают по 4 байта каждый. S>Это чрезмерно упрощенное представление. Сode points Unicode не занимают никакого количества байт; это натуральные числа.
Так я и упрощаю. Реально там немногим больше миллиона символов, что в 2 байта не влезает, а в 4 — влезает. Поэтому можно считать, что одна четвёрка байтов в utf-32 соответствует одному символу (раздел 2.5 пункт "fixed width")
S>Символ некоего алфавита не всегда имеет однозначное представление в виде code points, в частности, буква ё может быть представлена одним code point либо двумя (кириллическая е + две точки над ней). S>Любая кодировка (в том числе и utf-32) задает правила конверсии между байтовой последовательностью и цепочкой натуральных чисел. S>Таким образом, в зависимости от кодировки, та же буква ё может занимать от 1 до 8 байт.
Спасибо, я это знаю (кстати, почему до восьми? utf-8 — 2 байта, utf-16 — 2 байта, utf-32 — 4 байта. Неужели UTF-64?)
Но в контексте топика я не думаю, что имеет смысл расказывать весь стандарт, понятия о encoding forms (transfer functions) тут вполне достаточно.
Здравствуйте, neFormal, Вы писали:
F>Проверил, не utf32.
И как ты это проверял? F>Коды символов, переданные по сети такие же, как если бы писать utf8 в файл. Разница только в дополнительных байтах.
Эти дополнительные байты и есть UTF-32.
Вот файл.
Он прекрасно читается вот такой программой:
Здравствуйте, vmpire, Вы писали: V>Спасибо, я это знаю (кстати, почему до восьми? utf-8 — 2 байта, utf-16 — 2 байта, utf-32 — 4 байта.
4 байта на code point. Буква != code point. Я же написал, что букву (графему) ё можно представить как два код-поинта.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, neFormal, Вы писали:
F>Проверил, не utf32. F>Коды символов, переданные по сети такие же, как если бы писать utf8 в файл. Разница только в дополнительных байтах.
Тогда это какая-то своя кодировка, её нужно разбирать руками. Можно написать свой потомок класса Encoding, а там обрезать лишние нули и вызывать utf-8.
Только проверьте сначала, что это именно utf-8, передавая не латинские символы.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, vmpire, Вы писали: V>>Спасибо, я это знаю (кстати, почему до восьми? utf-8 — 2 байта, utf-16 — 2 байта, utf-32 — 4 байта. S>4 байта на code point. Буква != code point. Я же написал, что букву (графему) ё можно представить как два код-поинта.
А, точно, не обратил внимания что речь идёт именно о букве, извините
Здравствуйте, Sinclair, Вы писали:
F>>Проверил, не utf32. S>И как ты это проверял?
Encoding.UTF32.GetString()?. Не?.
Передал массив байт, получил иероглифы. Где я ошибся?.
F>>Коды символов, переданные по сети такие же, как если бы писать utf8 в файл. Разница только в дополнительных байтах. S>Эти дополнительные байты и есть UTF-32. S>Вот файл. S>Он прекрасно читается вот такой программой:
А gedit(стандартный редактор в Gnome) говорит:
Could not open the file /tmp/utf32.txt using the Unicode (UTF-32) character coding.
Вопрос в топик:
Как можно в плюсах указать использование utf8, если у кодировки плавающий размер?. Имхо использование размера "с запасом" как минимум логично..
Какие еще могут быть варианты?.
Здравствуйте, neFormal, Вы писали: F>Encoding.UTF32.GetString()?. Не?. F>Передал массив байт, получил иероглифы. Где я ошибся?.
Не знаю. Ты пока не привел пример строки, из которой ты получил иероглифы. Твой Hello прекасно прочитался, я тебе пример дал. Ты по какой-то непонятной мне причине отказываешься приводить примеры реального кода и реальных данных. Нам остается только телепатически гадать, где именно ты ошибся.
F>
Надо полагать, гном глючит. Ты на чем программируешь — на гноме или на дотнете?
F>Вопрос в топик: F>Как можно в плюсах указать использование utf8, если у кодировки плавающий размер?.
Гм. Наверное, точно так же. Нужно просто понимать, что "строка" и "строка в кодировке" — это не муж и жена, а четыре разных человека.
Строка — это цепочка символов, строка в кодировке — цепочка байт. F>Имхо использование размера "с запасом" как минимум логично.. F>Какие еще могут быть варианты?.
Варианты могут быть любые. Самый логичный — хранить строки в программе в формате, удобном для манипуляций, а передавать — в формате, удобном для передачи. UCS-2 и UCS-4 удобны тем, что к ним легко обращаться по индексу. (UTF16LE применяют редко, потому что в нем не все code points занимают 2 байта). UTF-8 удобен тем, что для латиницы хватает одного байта на букву. Не бывает одного тру енкодинга на все случаи жизни.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, neFormal, Вы писали: F>Проверяли вроде, русские символы занимают 2 байта вместо одного. F>Т.е. выглядит как: F>['П', 0, 0, 'р', 0, 0, 'и', 0, 0, 'в', 0, 0, 'е', 0, 0, 'т']
Ничего не понятно. Приведите шестнадцатеричное представление байтового массива. У вас получилось 16 элементов массива на 6 букв. Это какой-то бред.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
F>>Проверяли вроде, русские символы занимают 2 байта вместо одного. F>>Т.е. выглядит как: F>>['П', 0, 0, 'р', 0, 0, 'и', 0, 0, 'в', 0, 0, 'е', 0, 0, 'т'] S>Ничего не понятно. Приведите шестнадцатеричное представление байтового массива. У вас получилось 16 элементов массива на 6 букв. Это какой-то бред.
Здравствуйте, Sinclair, Вы писали:
S>Надо полагать, гном глючит. Ты на чем программируешь — на гноме или на дотнете?
Под гномом — сервер, под дотнетом — клиент.
К примеру, файлик в utf8 одинаково корректно читается и gedit-ом, и notepad-ом и тестовой программкой на .net-е.
S>Ты по какой-то непонятной мне причине отказываешься приводить примеры реального кода и реальных данных. Нам остается только телепатически гадать, где именно ты ошибся.
Извиняюсь, кода под рукой нет, чуть позже отпишусь снова, покажу конкретные примеры, когда сам у автора их заберу.