Страница 1 из 1

Какие могут быть грабли - STL+UNICODE+ xxx_string

Добавлено: 23 мар 2005, 19:34
vg
Сейчас в проекте не используестя UNICODE.
Как будет дальше - точно не знаю. Может быть. Раньше юзал для UNICODE просто LPCTSRT/LPTSRT или CString-и MFC для MBSC.

1) Допустимо ли обойтись использованием basic_string и простейшими определениями, типО:

#include <vector>
#include <string>
#include <tchar.h>

//-----------------------------------------------------------------------------

typedef std::basic_string <TCHAR> _tstring;

====================================================

2) Или надо анализировать определения _UNICODE, как это делается, например, в <tchar.h>, типа :

#ifdef _UNICODE
typedef wstring _tstring;
#else
#ifdef _MBSC
typedef string _tstring;
#endif
#endif

Возможно, что есть разница в п.1 и п.2.

Спасибо.

Добавлено: 23 мар 2005, 21:17
Lepsik
можно и так и так. А чем тебя wstring не устраивает ?

Добавлено: 23 мар 2005, 21:38
vg
Lepsik писал(а):можно и так и так. А чем тебя wstring не устраивает ?
Надо, чтобы комптлтровалось и так, и так. Пока всё будет в не юникодной версии - string. Для UNICODE - wstring лично меня устраивает. Должно быть конечно правильно. Народ как-то вяло отвечает везде, что _вроде_ нормально. Это-то и плохо. Это от недостатка опыта. Вот посмотри, не всё так гладко:
http://www.codeproject.com/vcpp/stl/upg ... nicode.asp

Я про "негладкости" из _практического_ опыта и хотел узнать. Проблема-то в том, что мало, если у чела компилируется и в юникоде и не в юникоде. Это-то прокатит. Проблемы могут быть совершенно неожиданые потом. И увидишь это по крозябрам в лучшем случае.
Ещё на RSDN есть маленько инфы.

Добавлено: 24 мар 2005, 00:19
ajkj3em
если не нужно интегрироваться с mfc, то string в принципе достаточно.

ключевое слово тут - utf8. всякая ascii строка (то есть с символами от 0 до 127) является utf8. Поэтому, если есть код который написан на string'ах под обычные ascii данные, то добавление поддержки ucs (см ниже) сводится к замене класса string на utf8. Все существующие данные при этом автоматом сохраняются и никакой переконвертации не требуют.

ps. обычно задача стоит добавить не unicode support, а именно ucs. ucs - это непосредственные таблицы символов определенные неким стандартом. utf8 и unicode - это кодировки, то есть mapping таблиц ucs символов на конкретные mutli- или 2х-байтовые значения. более-менее свежие винды (2000+) поддерживают обе кодировки, unicode является native (шуршит быстрее), но он iirc не покрывает весь алфавит.

pps. http://www.nada.kth.se/i18n/ucs/unicode ... oview.html

Добавлено: 24 мар 2005, 06:03
vg
drain bamage писал(а):если не нужно интегрироваться с mfc, то string в принципе достаточно.
Спасибо за реакцию. Пока поддержки MFC, к сожалению, не избежать (в других частях проекта, не моих). Потом - не знаю. Зависит от архитектора. В своих же модулях стараюсь избегать поддержки этого каркаса. Все символы, экспоритируемые из своих модулей и касающиеся строк, буду делать LPCTSTR. Для последующего использования этих модулей MFC-шниками тоже (они используют там CString с _MBSC, а не _UNICODE).

Добавлено: 24 мар 2005, 22:49
vg
drain bamage писал(а):если не нужно интегрироваться с mfc, то string в принципе достаточно.

ключевое слово тут - utf8. всякая ascii строка (то есть с символами от 0 до 127) является utf8. Поэтому, если есть код который написан на string'ах под обычные ascii данные, то добавление поддержки ucs (см ниже) сводится к замене класса string на utf8. Все существующие данные при этом автоматом сохраняются и никакой переконвертации не требуют.

ps. обычно задача стоит добавить не unicode support, а именно ucs. ucs - это непосредственные таблицы символов определенные неким стандартом. utf8 и unicode - это кодировки, то есть mapping таблиц ucs символов на конкретные mutli- или 2х-байтовые значения. более-менее свежие винды (2000+) поддерживают обе кодировки, unicode является native (шуршит быстрее), но он iirc не покрывает весь алфавит.

pps. http://www.nada.kth.se/i18n/ucs/unicode ... oview.html
А вообще ты меня смутил... Вот уже ночь, а я всё заснуть не могу. Предполалагаю, что поддержка азиатских символов за пределами ucs-2 может и понадобиться. Хотя нет оснований сейчас волноваться в части кодирования utf-8, поскольку это будут только internal фукции. Вроде винда умеет это делать при помощи "суррогатов" для случая, если unicode символ уже не удаётся представить единственным 16-битным значением.
В этом случае _tstring(см. выше) - это просто где-то удобные (теперь всё более понятно, что не везде) буферы WCHAR (теперь уже немного смешно про WCHAR, когда я немного почитал;)) ). А вот то, как работать с этим буфером - дело API (в зависимости от того, что будет указано в аргументах функций о способе кодирования unicode (utf/ucs ) ).

... и ещё подскажи, если я не прав...
wstring ничего не знают ( и не могут знать ) про способы кодирования unicode.
При этом они считают строку нуль терминированной. Возможна ли ситуация когда, например, один из байтов, пусть, трёхбайтного символа (в utf-8) в середине строки будет равен нулю? Если да, что где гарантия, что wstring не примет это за терминатор строки? Если нет гарантий - ... то про все функции, где wstring вычисляет свою длину придётся забыть. Если продолжить в том же духе, то в таком случае вообще не вижу особого смысла использовать STL строки для _UNICODE в общем случае (когда длина символа переменная != 2 байт, и один из байт равен 0). Использовать только API + LPCTSTR.

Не уверен, конечно, что utf - байты последовательностей кодирования unicode могут быть нулевыми. Но даже в этом случае, как wstring определит длину "себя", если она не умеет различать отдельные символы в последовательности байтов. Польза тогда от wstring - сомнительная.

Добавлено: 25 мар 2005, 14:26
ajkj3em
В utf-8 нулевой байт не встречается ни в одном символе кроме
самого NULL. В комитете по стандартам тоже не дураки сидят :)

Более того utf-8 устроен так, что первый байт любого символа
отличается (каким-то там битом) от всех последующих, что собсно
значительно упрощает все строковые операции, где нужно знать
границы индивидуальных символов.

Добавлено: 25 мар 2005, 15:06
vg
drain bamage писал(а):В utf-8 нулевой байт не встречается ни в одном символе кроме
самого NULL. В комитете по стандартам тоже не дураки сидят :)

Более того utf-8 устроен так, что первый байт любого символа
отличается (каким-то там битом) от всех последующих, что собсно
значительно упрощает все строковые операции, где нужно знать
границы индивидуальных символов.
Спасибо за комментарий. У меня там ляп ещё ... вверху :oops: . Не спал вчера. Думал про одно, писал другое. :D Не буду смывать это с доски позора. :D

Да, и ещё ... у меня сегодня психоз на почве того, что не получаются вообще самые элементарные вещи. :oops: Как говорил, уважаемый Циник - смешались люди и кони в голове. Сейчас причешу код. Задам вопросы.

Добавлено: 26 мар 2005, 15:19
Lepsik
Unicode завершается двумя нулями, так что смело используй ноль.

Добавлено: 26 мар 2005, 20:21
vg
Lepsik писал(а):Unicode завершается двумя нулями, так что смело используй ноль.
Ты, будешь смеяться, но бывают однобайтовые строки, содержащие UNICODE - коды. Заметь это вполне нормальные, соответствующие стандартам UTF “UNICODE” строки. Всё зависит от того, какие символы мапятся. Для кодирования UNICODE символов вовсе не обязательно всегда использовать два байта на код символа. Это миф, который придумал MS (UTF-16, на самом деле называется). Например, UTF-8 использует от одного до шести байт в последовательности. Имеется в виду именно коды UCS. Ещё раз буквально – бывают строки, содержащие UNICODE символы, которые передаются как обычные строки. Для них достаточно одного завершающего нуля.

Ты прав (с практической точки зрения программера – почитателя MS). Поскольку же ты программер нормальный, а не просто почитатель MS, то мне кажется, что нужно подправить терминологию. С терминологической же точки зрения ... Говоря «строка UNICODE», что ты имеешь ввиду? Как транслированный (вернее трансформированный)? UTF-8? UTF-16? UTF -32 … BE? LE? Про трансформацию я к тому, что "линейное" отображение UTF-16 (то, что считает своей заслугой MS :lol:, называя строками UNICODE, и то, что имеешь ввиду ты, вероятно) на пространство UCS – это тоже, как не странно, вид трансформации.

Повторяю. Ты прав с практической точки зрения, учитывая устоявшуюся практику называть трансляцию UCS-2 (c некоторыми усовершенствованиями и UCS-4) с пользованием кодировки с фиксированной шириной символа (16 бит) "UNICODE-ом". Лучше было б всё ж говорить UTF-16 (BE/LE)…
Чтоб было понятнее, например, кодированная в UTF-8 строка UNICODE - это не UNICODE строка в твоём понимании, поскольку является способом кодирования с плавающей шириной представления "символа" UNICODE. В отличие от микрософтовского понимания UNICODE == два байта на символ, здесь используется от одного до шести байт в последовательности. Т.е первый символ в потоке – один байт, второй символ – 4 байт ….

Всё равно, спасибо за реакцию. Ты прав - wstring вполне подходит для написания классов обработки UTF-16. Здесь и не было сомнений. Народ успешно использует и для UTF-8. Пока не уверен здесь, что будет удобно и мне. Проблема и не в том, что я буду использовать UTF-8. Проблема в том, что программер может в принципе использовать MBC Microsoft c плавающей шириной символа. Здесь строка из двух литер может занимать, например, 3 байта (без учёта нуль-терминатора). Короче, как-то надо хранить и информацию о способе кодирования.

ЗЫ. Поправь, если я от недалёкости чего не так сказал.

Добавлено: 26 мар 2005, 20:59
vg
drain bamage писал(а):В utf-8 нулевой байт не встречается ни в одном символе кроме
самого NULL.
Ещё раз спасибо за комментарий. Это заставило меня маненько поработать. Ну, а про NULL (см. выше) – да, я проверил. Так и есть.
drain bamage писал(а):… (каким-то там битом) от всех последующих, что собсно
значительно упрощает все строковые операции, где нужно знать
границы индивидуальных символов.
Действительно. Идея у разработчиков стандарта оказалась простой и эффективной. При этом такие “UNICODE” строки получаются очень компактны.

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

RFC 2279                         UTF-8                      January 1998


   UCS-4 range (hex.)           UTF-8 octet sequence (binary)
   0000 0000-0000 007F   0xxxxxxx
   0000 0080-0000 07FF   110xxxxx 10xxxxxx
   0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx

   0001 0000-001F FFFF   11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
   0020 0000-03FF FFFF   111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
   0400 0000-7FFF FFFF   1111110x 10xxxxxx ... 10xxxxxx
http://www.faqs.org/rfcs/rfc2279.html

Т.е. действительно очень просто анализировать – два первых бита установлены – два байта в последовательности на символ. Три бита установлены в лид-байте – три байта в последовательности ….
Код получается простым. Вот фрагмент кода одного программера:

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

            // Determine whether we are dealing
            // with a one-, two-, three-, or four-
            // byte sequence.
      if ((b1 & 0x80) == 0) 
      {
          // 1-byte sequence: 000000000xxxxxxx = 0xxxxxxx
          <skip>      } 
      else if ((b1 & 0xe0) == 0xc0) 
      {
          // 2-byte sequence: 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
          <skip>      } 
      else if ((b1 & 0xf0) == 0xe0) 
      {
          // 3-byte sequence: zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
           <skip>      } 
      else if ((b1 & 0xf8) == 0xf0) 
      {
          // 4-byte sequence: 11101110wwwwzzzzyy + 110111yyyyxxxxxx
           <skip>      
           <skip>       
http://www.rsdn.ru/Forum/Message.aspx?mid=246668&only=1

Кстати, есть ещё одна интересная с практической точки зрения особенность, которая отмечена программистами ASPLinux:

“…UTF-8 является самосинхронизирующимся: 10xxxxxx - это "хвост", а любой другой байт - "голова" кода.…” Разумеется, это должно облегчить парсинг, контроль. Повысить надёжность передачи строк с «битыми» символами.
Можно почитать:
http://www.linuxdoc.ru/manpages/man7/charsets.7.html
http://www.linuxdoc.ru/manpages/man7/utf-8.7.html