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ます。サロゲートペア(1つのUnicode文字)は2つのwchar_tを使用するため、サイズに2が追加されます。

basic_string<wchar_t>::resize()サロゲートペアの途中で文字列を切り捨てることができます。

basic_string<wchar_t>::insert()サロゲートペアの中央に挿入できます。

basic_string<wchar_t>::erase()サロゲートペアのいずれかの半分を消去できます。

一般に、パターンは明確である必要があります。STLは、aがUTF-16にあるとは想定せずstd::wstring、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。他の関数の機能を使用して、エンコーディングの問題に対処する必要があります。

于 2010-10-26T16:06:34.480 に答える
4

2つのこと:

  1. 「MicrosoftSTLの実装」はありません。Visual C++に同梱されているC++標準ライブラリは、Dinkumwareからライセンス供与されています。
  2. 現在のC++標準は、Unicodeとそのエンコード形式について何も知りません。std :: wstringは、Windowsではたまたま16ビットであるwchar_tユニットの単なるコンテナです。実際には、UTF-16でエンコードされた文字列をwstringに格納する場合は、コードポイントではなく、実際にコードユニットを格納していることを考慮に入れてください。
于 2010-10-26T16:33:14.703 に答える
0

MSVCはsに格納wchar_twstringます。これらは、Unicode 16ビットワード、または実際には他のものとして解釈できます。

Unicode文字またはグリフにアクセスする場合は、上記の生の文字列をUnicode標準で処理する必要があります。また、一般的なコーナーケースを壊さずに処理したいと思うかもしれません。

これがそのようなライブラリのスケッチです。これは、メモリ効率の約半分ですが、のユニコードグリフへのインプレースアクセスを提供しますstd::string。それはまともなクラスを持っていることに依存してarray_viewいますが、とにかくそれらの1つを書きたいと思います:

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よりコンパクトな実装では、前の終了ポインターと次の開始ポインターが常に同一であるという事実を追跡し、それらを一緒にエイリアスします。もう1つの最適化は、ほとんどのグリフが1文字であるという仮定に基づいて、グリフに小さなオブジェクトの最適化を使用し、2文字の場合は動的割り当てを使用することです。

私はCGJを標準の発音区別符号として扱い、二重発音区別符号は1つ(ユニコード)を形成する3文字のセットとして扱いますが、半発音区別符号は物事を1つのグリフにマージしないことに注意してください。これらはすべて疑わしい選択です。

これは不眠症の発作で書かれました。少なくともある程度は機能することを願っています。

于 2014-09-24T04:04:17.987 に答える