Как Microsoft обрабатывает тот факт, что UTF-16 является кодировкой переменной длины в их стандартной реализации библиотеки C ++ - PullRequest
11 голосов
/ 26 октября 2010

Кодирование переменной длины в стандарте косвенно запрещено.

Поэтому у меня есть несколько вопросов:

Как обрабатывается следующая часть стандарта?

17.3.2.1.3.3 Последовательности широких символов

Последовательность широких символов - это объект массива (8.3.4) A, который может быть объявлен как TA [N], где T - тип wchar_t (3.9.1), необязательно квалифицируется по любой комбинации const или volatile.Начальные элементы массива имеют определенное содержимое вплоть до элемента, определенного некоторым предикатом.Последовательность символов может быть обозначена значением указателя S, которое обозначает его первый элемент.

Длина NTWCS - это количество элементов, которые предшествуют завершающему нулевому широкому символу.Пустая NTWCS имеет нулевую длину.

Вопросы:

basic_string<wchar_t>

  • Как реализовано operator[] и что оно возвращает?
    • стандарт: If pos < size(), returns data()[pos]. Otherwise, if pos == size(), the const version returns charT(). Otherwise, the behavior is undefined.
  • Возвращает ли size() количество элементов или длину строки?
    • стандарт: Returns: a count of the number of char-like objects currently in the string.
  • Как работает resize()?
    • не имеет отношения к стандарту, что он делает
  • Как обрабатываются позиции в insert(), erase() и других?

cwctype

  • Практически все здесь.Как обрабатывается кодировка переменной?

cwchar

  • getwchar(), очевидно, не может вернуть целый символ платформы, так как это работает?

Плюс все остальные функции персонажа (тема та же).

Редактировать: Я открою щедрость, чтобы получить подтверждение.Я хочу получить четкие ответы или хотя бы более четкое распределение голосов.

Редактировать: Это начинает становиться бессмысленным.Это полно совершенно противоречивых ответов.Некоторые из вас говорят о внешних кодировках (меня это не волнует, кодировка UTF-8 все равно будет сохранена как UTF-16 после чтения в строку, то же самое для вывода), остальные просто противоречат друг другу.: - /

Ответы [ 5 ]

15 голосов
/ 27 октября 2010

Вот как реализация Microsoft STL обрабатывает кодирование переменной длины:

basic_string<wchar_t>::operator[])( может возвращать низкий или высокий суррогат, отдельно.

basic_string<wchar_t>::size() возвращает число wchar_t предметов.Суррогатная пара (один символ Unicode) использует два wchar_t и, следовательно, добавляет два к размеру.

basic_string<wchar_t>::resize() может обрезать строку в середине суррогатной пары.

basic_string<wchar_t>::insert() canвставить в середину суррогатной пары.

basic_string<wchar_t>::erase() может стереть любую половину суррогатной пары.

В общем, картина должна быть ясной: STL не предполагает, что a std::wstring находится в UTF-16, и не обеспечивает, что он остается UTF-16.

9 голосов
/ 26 октября 2010

STL рассматривает строки как простую оболочку для массива символов, поэтому size () или length () в строке STL сообщит вам, сколько элементов char или wchar_t оно содержит, а не обязательно количество печатаемых символов. в строке.

8 голосов
/ 26 октября 2010

Предполагая, что вы говорите о типе wstring, кодировка не обрабатывается - она ​​работает только с элементами wchar_t, ничего не зная о кодировке.Это просто последовательность wchar_t.Вам нужно будет решить проблемы с кодированием, используя функциональность других функций.

4 голосов
/ 26 октября 2010

Две вещи:

  1. Нет "реализации Microsoft STL".Стандартная библиотека C ++, поставляемая с Visual C ++, лицензирована у Dinkumware.
  2. Текущий стандарт C ++ ничего не знает о Unicode и его формах кодирования.std :: wstring - это просто контейнер для модулей wchar_t, которые в Windows оказались 16-битными.На практике, если вы хотите сохранить строку в кодировке UTF-16 в строке wstring, просто учтите, что вы действительно храните единицы кода, а не точки кода.
0 голосов
/ 24 сентября 2014

MSVC хранит wchar_t в wstring с. Их можно интерпретировать как 16-битные слова в кодировке Unicode или что-то еще.

Если вы хотите получить доступ к символам или символам Юникода, вам придется обрабатывать указанную необработанную строку по стандарту Юникода. Вы, вероятно, также хотите обрабатывать обычные угловые дела без поломок.

Вот эскиз такой библиотеки. Это примерно вдвое эффективнее, чем память, но дает вам доступ к глифам Юникода на месте в std::string. Он опирается на приличный класс array_view, но вы все равно хотите написать один из них:

struct unicode_char : array_view<wchar_t const> {
  using array_view<wchar_t const>::array_view<wchar_t const>;

  uint32_t value() const {
    if (size()==1)
      return front();
    Assert(size()==2);
    if (size()==2)
    {
      wchar_t high = front()-0xD800;
      wchar_T low = back()-0xDC00;
      return (uint32_t(high)<<10) + uint32_t(low);
    }
    return 0; // error
  }
  static bool is_high_surrogate( wchar_t c ) {
    return (c >= 0xD800 && c <= 0xDBFF);
  }
  static bool is_low_surrogate( wchar_t c ) {
    return (c >= 0xDC00 && c <= 0xDFFF);
  }
  static unicode_char extract( array_view<wchar_t const> raw )
  {
    if (raw.empty())
      return {};
    if (raw.size()==1)
      return raw;
    if (is_high_surrogate(raw.front()) && is_low_surrogate(*std::next(raw.begin())))
      return {raw.begin(), raw.begin()+2);
    return {raw.begin(), std::next(raw.begin())};
  }
};
static std::vector<unicode_char> as_unicode_chars( array_view<wchar_t> raw )
{
  std::vector<unicode_char> retval;
  retval.reserve( raw.size() ); // usually 1:1
  while(!raw.empty())
  {
    retval.push_back( unicode_char::extract(raw) );
    Assert( retval.back().size() <= raw.size() );
    raw = {raw.begin() + retval.back().size(), raw.end()};
  }
  return retval;
}
struct unicode_glyph {
  std::array< unicode_char, 3 > buff;
  std::size_t count=0;
  unicode_char const* begin() const {
    return buff.begin();
  }
  unicode_char const* end() const {
    return buff.begin()+count;
  }
  std::size_t size() const { return count; }
  bool empty() { return size()==0; }
  unicode_char const& front() const { return *begin(); }
  unicode_char const& back() const { return *std::prev(end()); }
  array_view< unicode_char const > chars() const { return {begin(), end()}; }
  array_view< wchar_t const > wchars() const {
    if (empty()) return {};
    return { front().begin(), back().end() };
  }

  void append( unicode_char next ) {
    Assert(count<3);
    buff[count++] = next;
  }
  unicode_glyph() {}

  static bool is_diacrit(unicode_char c) const {
    auto v = c.value();
    return is_diacrit(v);
  }
  static bool is_diacrit(uint32_t v) const {
    return
      ((v >= 0x0300) && (v <= 0x0360))
    || ((v >= 0x1AB0) && (v <= 0x1AFF))
    || ((v >= 0x1DC0) && (v <= 0x1DFF))
    || ((v >= 0x20D0) && (v <= 0x20FF))
    || ((v >= 0xFE20) && (v <= 0xFE2F));
  }
  static size_t diacrit_count(unicode_char c) const {
    auto v = c.value();
    if (is_diacrit(v))
      return 1 + ((v >= 0x035C)&&(v<=0x0362));
    else
      return 0;
  }
  static unicode_glyph extract( array_view<const unicode_char> raw ) {
    unicode_glyph retval;
    if (raw.empty())
      return retval;
    if (raw.size()==1)
    {
      retval.append(raw.front());
      return retval;
    }
    retval.count = diacrit_count( *std::next(raw.begin()) )+1;
    std::copy( raw.begin(), raw.begin()+retval.count, retval.buff.begin() );
    return retval;
  }
};
static std::vector<unicode_glyph> as_unicode_glyphs( array_view<unicode_char> raw )
{
  std::vector<unicode_glyph> retval;
  retval.reserve( raw.size() ); // usually 1:1
  while(!raw.empty())
  {
    retval.push_back( unicode_glyph::extract(raw) );
    Assert( retval.back().size() <= raw.size() );
    raw = {raw.begin() + retval.back().size(), raw.end()};
  }
  return retval;
}
static std::vector<unicode_glyph> as_unicode_glyphs( array_view<wchar_t> raw )
{
  return as_unicode_glyphs( as_unicode_chars( raw ) );
}

более умный бит кода будет генерировать unicode_char s и unicode_glyph s на лету с фабричным итератором некоторого вида. Более компактная реализация отслеживала бы тот факт, что указатель конца предыдущего и указатель начала следующего всегда идентичны и объединяли их вместе. Другая оптимизация заключалась бы в использовании оптимизации небольших объектов на глифе, основанной на предположении, что большинство глифов - это один символ, и использовании динамического выделения, если их два.

Обратите внимание, что я рассматриваю CGJ как стандартный диакрит, а двойные диакриты - как набор из 3 символов, которые образуют один (юникод), но полудиакриты не объединяют вещи в один глиф. Это все сомнительные варианты.

Это было написано в приступе бессонницы. Надеюсь, это хоть как-нибудь сработает.

...