2012-04-21 19 views
8

Giriş

std::string text = "á"; 

"á" (UTF-8 kodlamasını varsayarak) iki baytlık karakterdir.
Yani aşağıdaki satırı baskılarboost :: property_tree :: json_parser ve iki baytlık geniş karakterler

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

2. Ama std::cout hala metni doğru yazdırır.

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

Ben textboost::property_tree::ptree ve daha sonra farklı olan

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

metin için "Â ¡" eşittir sonucudur 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"; 

geçmek

Sorunum "á" dan.

std::wstring'a dönmeden bu sorunu çözmek mümkün mü? Değişen kitaplığın (boost::property_tree::ptree) bu sorunu çözmesi mümkün mü?

cevap

10

Bazı çözümler buldum. Genel olarak "özel günler hatasız kaçış" sağlamak için [Ch=Char] için boost::property_tree::json_parser::create_escapes şablonunu belirtmeniz gerekir. Standart

JSON tüm dize UTF-16 "\ uXXXX" kaçan kodlanmış olduğunu kabul, ama "\ xxx" ile bazı kütüphane desteği UTF-8 kodlaması kaçan. JSON dosyası UTF-8'de kodlanmışsa, 0x7F'den daha büyük olan tüm karakterleri geçirebilir, cadı orijinal işlev için tasarlanmıştır.

Bu kodu boost::property_tree::json_parser::write_json kullanmadan önce koyuyorum.

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; 
    } 
} } } 

Ve çıkış alıyorum: Bu boost_1_49_0/boost/property_tree/detail/json_parser_write.hpp gelen okuma imzalı chars Unicode karakterleri atlanmış

{ 
    "text": "aáb" 
} 

Ayrıca fonksiyon boost::property_tree::json_parser::a_unicode benzer sorunları var. Temel Multilingual düzlemi üzerinde

+1

teşekkürler. Boost :: property_tree :: json_parser :: create_escapes' ile Nice bul. Çözümünüz kesinlikle bir gelişme. Ama ben tüm UTF-8 karakter kümesi için çalışacağını sanmıyorum /. Ben haklı mıyım –

+2

0x7F üzerindeki Unicode karakterini kodlayan tüm baytlar 0x7F'nin üzerinde (imzalı char için 0'ın altında) olduğundan, bu işlev UTF-8 üzerinden doğru şekilde iletilir. Bazı unicode karakterleri elbette yazdırılamayabilir ve bazı UTF-8 dizileri asla görünmemelidir. – Arpegius

+0

JSON standardı, kodlama hakkında herhangi bir varsayımda bulunmaz. RFC 46273'e göre. Kodlama JSON metni Unicode olarak kodlanmalıdır. Varsayılan kodlama UTF-8'dir. JSON metninin ilk iki karakteri her zaman ASCII karakterleri [RFC0020] olduğundan, akışının bir UTF-8, UTF-16 (BE veya LE) veya UTF-32 olup olmadığını belirlemek mümkündür (BE veya LE) 'u ilk dört sekizeteki sıfırların yapısına bakarak görebilirsiniz. 00 00 00 xx UTF-32BE 00 xx 00 xx UTF-16BE xx 00 00 00 UTF-32LE xx 00 xx 00 UTF-16LE xx xx xx xx UTF-8 –

-1

Destek: Cevabınız için

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; 
} 
İlgili konular