2012-04-21 15 views
8

はじめ

std::string text = "á"; 

"A" は(UTF-8エンコーディングを仮定した場合)2バイト文字です。
したがって、次の行を印刷ブースト:: property_tree :: json_parserと2バイト幅の文字

std::cout << text.size() << "\n"; 

2.しかしstd::coutが正常にテキストを出力します。

std::cout << text << "\n"; 

私の問題

私はboost::property_tree::ptreetextを渡した後、write_json

boost::property_tree::ptree root; 
root.put<std::string>("text", text); 

std::stringstream ss; 
boost::property_tree::json_parser::write_json(ss, root); 
std::cout << ss.str() << "\n"; 

に結果が

{ 
    "text": "\u00C3\u00A1" 
} 

テキストが異なる "á" に等しいです"á"より。

std::wstringに切り替えることなくこの問題を解決することは可能ですか?ライブラリ(boost::property_tree::ptree)を変更することでこの問題を解決できる可能性はありますか?

答えて

10

解決策がいくつか見つかりました。 一般的には[Ch=Char]のテンプレートboost::property_tree::json_parser::create_escapesを指定する必要があります。これは、「特別な機会にバグを逃さないようにする」ためです。

JSON標準では、すべての文字列が "\ uXXXX"でエスケープされたUTF-16であると仮定していますが、一部のライブラリでは "\ xXX"をエスケープするUTF-8エンコーディングがサポートされています。 JSONファイルをUTF-8でエンコードすることができれば、元の機能を意図した0x7F以上のすべての文字を渡すことができます。

boost::property_tree::json_parser::write_jsonを使用する前にこのコードを入力しました。それはboost_1_49_0/boost/property_tree/detail/json_parser_write.hppから来ている:

namespace boost { namespace property_tree { namespace json_parser 
{ 
    // Create necessary escape sequences from illegal characters 
    template<> 
    std::basic_string<char> create_escapes(const std::basic_string<char> &s) 
    { 
     std::basic_string<char> result; 
     std::basic_string<char>::const_iterator b = s.begin(); 
     std::basic_string<char>::const_iterator e = s.end(); 
     while (b != e) 
     { 
      // This assumes an ASCII superset. But so does everything in PTree. 
      // We escape everything outside ASCII, because this code can't 
      // handle high unicode characters. 
      if (*b == 0x20 || *b == 0x21 || (*b >= 0x23 && *b <= 0x2E) || 
       (*b >= 0x30 && *b <= 0x5B) || (*b >= 0x5D && *b <= 0xFF) //it fails here because char are signed 
       || (*b >= -0x80 && *b < 0)) // this will pass UTF-8 signed chars 
       result += *b; 
      else if (*b == char('\b')) result += char('\\'), result += char('b'); 
      else if (*b == char('\f')) result += char('\\'), result += char('f'); 
      else if (*b == char('\n')) result += char('\\'), result += char('n'); 
      else if (*b == char('\r')) result += char('\\'), result += char('r'); 
      else if (*b == char('/')) result += char('\\'), result += char('/'); 
      else if (*b == char('"')) result += char('\\'), result += char('"'); 
      else if (*b == char('\\')) result += char('\\'), result += char('\\'); 
      else 
      { 
       const char *hexdigits = "ABCDEF"; 
       typedef make_unsigned<char>::type UCh; 
       unsigned long u = (std::min)(static_cast<unsigned long>(
               static_cast<UCh>(*b)), 
              0xFFFFul); 
       int d1 = u/4096; u -= d1 * 4096; 
       int d2 = u/256; u -= d2 * 256; 
       int d3 = u/16; u -= d3 * 16; 
       int d4 = u; 
       result += char('\\'); result += char('u'); 
       result += char(hexdigits[d1]); result += char(hexdigits[d2]); 
       result += char(hexdigits[d3]); result += char(hexdigits[d4]); 
      } 
      ++b; 
     } 
     return result; 
    } 
} } } 

そして私が手出力:

{ 
    "text": "aáb" 
} 

また機能boost::property_tree::json_parser::a_unicodeは読書と同様の問題が署名した文字にUnicode文字をエスケープしています。基本多言語面上の

+1

感謝。ニースは 'boost :: property_tree :: json_parser :: create_escapes'で見つけることができます。あなたのソリューションは間違いなく改善です。しかし、UTF-8文字セット全体ではうまくいかないと思います。私は正しい? –

+2

0x7F以上のUnicode文字をコードするすべてのバイトは、0x7F(符号付き文字の場合は0未満)以上であるため、この関数はUTF-8を正しく通過します。一部のUnicode文字は印刷できない場合があり、UTF-8シーケンスは決して表示されません。 – Arpegius

+0

JSON標準では、エンコードについての前提はありません。 Per RFC 46273。エンコーディング JSONテキストはUnicodeでエンコードされます。デフォルトのエンコーディングは UTF-8です。 JSONテキストの最初の2文字は常にASCII 文字[RFC0020]であるため、オクテット ストリームがUTF-8、UTF-16(BEまたはLE)かUTF-32(UTF- BEまたはLE)の最初の4オクテットでヌルのパターンで を見てください。 00 00 00 XX UTF-32BE 00 XX XX 00 UTF-16BE XX 00 00 00 UTF-32LE XX XX 00 00 UTF-16LE XX XX XX XX UTF-8 –

-1

サポート:あなたの答えのための

template<class Ch> 
std::basic_string<Ch> create_escapes(const std::basic_string<Ch> &s) 
{ 
    std::basic_string<Ch> result; 
    typename std::basic_string<Ch>::const_iterator b = s.begin(); 
    typename std::basic_string<Ch>::const_iterator e = s.end(); 
    while (b != e) 
    { 
     if (*b == 0x20 || *b == 0x21 || (*b >= 0x23 && *b <= 0x2E) || 
      (*b >= 0x30 && *b <= 0x5B) || (*b >= 0x5D && *b <= 0x80)) 
      result += *b; 
     else if (*b == Ch('\b')) result += Ch('\\'), result += Ch('b'); 
     else if (*b == Ch('\f')) result += Ch('\\'), result += Ch('f'); 
     else if (*b == Ch('\n')) result += Ch('\\'), result += Ch('n'); 
     else if (*b == Ch('\r')) result += Ch('\\'), result += Ch('r'); 
     else if (*b == Ch('/')) result += Ch('\\'), result += Ch('/'); 
     else if (*b == Ch('"')) result += Ch('\\'), result += Ch('"'); 
     else if (*b == Ch('\\')) result += Ch('\\'), result += Ch('\\'); 
     else 
     { 
      const char * hexdigits = "ABCDEF"; 

      typedef typename make_unsigned<Ch>::type UCh; 
      unsigned long u = static_cast<unsigned long>(static_cast<UCh>(*b)); 

      if (u <= 0xFFFF) 
      {    
       int d1 = u/4096; u -= d1 * 4096; 
       int d2 = u/256; u -= d2 * 256; 
       int d3 = u/16; u -= d3 * 16; 
       int d4 = u; 

       result += Ch('\\'); result += Ch('u'); 
       result += Ch(hexdigits[d1]); result += Ch(hexdigits[d2]); 
       result += Ch(hexdigits[d3]); result += Ch(hexdigits[d4]); 
      } 
      else 
      { 
       u = (((static_cast<unsigned long>(static_cast<UCh>(*b)) - 0x10000) >> 10) & 0x3ff) + 0xd800; 

       int d1 = u/4096; u -= d1 * 4096; 
       int d2 = u/256; u -= d2 * 256; 
       int d3 = u/16; u -= d3 * 16; 
       int d4 = u; 

       result += Ch('\\'); result += Ch('u'); 
       result += Ch(hexdigits[d1]); result += Ch(hexdigits[d2]); 
       result += Ch(hexdigits[d3]); result += Ch(hexdigits[d4]); 

       u = ((static_cast<unsigned long>(static_cast<UCh>(*b)) - 0x10000) & 0x3ff) + 0xdc00; 

       d1 = u/4096; u -= d1 * 4096; 
       d2 = u/256; u -= d2 * 256; 
       d3 = u/16; u -= d3 * 16; 
       d4 = u; 

       result += Ch('\\'); result += Ch('u'); 
       result += Ch(hexdigits[d1]); result += Ch(hexdigits[d2]); 
       result += Ch(hexdigits[d3]); result += Ch(hexdigits[d4]); 
      } 
     } 
     ++b; 
    } 
    return result; 
} 
関連する問題