11

标准中间接禁止使用可变长度编码。

所以我有几个问题:

标准的以下部分如何处理?

17.3.2.1.3.3 宽字符序列

宽字符序列是可以声明为 TA[N] 的数组对象 (8.3.4) A,其中 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,输出相同),其余的只是相互矛盾。:-/

4

5 回答 5

15

以下是 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()可以插入代理对的中间。

basic_string<wchar_t>::erase()可以擦除代理对的任何一半。

一般来说,模式应该很清楚:STL 不假定 astd::wstring是 UTF-16 格式,也不强制它保持 UTF-16 格式。

于 2010-10-27T10:08:44.063 回答
9

STL 将字符串处理为简单的字符数组的包装器,因此 STL 字符串上的 size() 或 length() 将告诉您它包含多少 char 或 wchar_t 元素,而不一定是字符串中的可打印字符数.

于 2010-10-26T16:05:11.700 回答
8

假设您正在谈论wstring类型,则不会处理编码 - 它只处理wchar_t元素而不知道任何关于编码的内容。这只是一个wchar_t's 的序列。您需要使用其他功能的功能来处理编码问题。

于 2010-10-26T16:06:34.480 回答
4

两件事情:

  1. 没有“Microsoft STL 实现”。Visual C++ 附带的 C++ 标准库由 Dinkumware 授权。
  2. 当前的 C++ 标准对 Unicode 及其编码形式一无所知。std::wstring 只是 wchar_t 单元的容器,在 Windows 上恰好是 16 位。实际上,如果您想将 UTF-16 编码的字符串存储到 wstring 中,只需考虑到您实际上存储的是代码单元而不是代码点。
于 2010-10-26T16:33:14.703 回答
0

MSVC 存储wchar_twstrings 中。这些可以解释为 unicode 16 位字,或者其他任何东西。

如果您想访问 unicode 字符或字形,则必须按 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_chars 和s 。unicode_glyph更紧凑的实现将跟踪这样一个事实,即前一个的结束指针和下一个的开始指针总是相同的,并将它们别名在一起。另一种优化是基于大多数字形是一个字符的假设对字形使用小对象优化,如果它们是两个则使用动态分配。

请注意,我将 CGJ 视为标准变音符号,将双变音符号视为一组 3 个字符组成一个(unicode),但半变音符号不会将事物合并到一个字形中。这些都是值得怀疑的选择。

这是在一次失眠症中写的。希望它至少在某种程度上有效。

于 2014-09-24T04:04:17.987 回答