Задача: Утилиты
Исходник: std::string <-> std::wstring, язык: C++ [code #576, hits: 12718]
автор: - [добавлен: 12.01.2009]
  1. // str_convert.hpp:
  2.  
  3. #ifndef VR_STR_CONVERTER_HPP
  4. #define VR_STR_CONVERTER_HPP
  5.  
  6. #include <string>
  7. #include <memory> // either from boost::tr1 or VS8 distribution.
  8. #include <locale>
  9.  
  10. namespace vr { namespace str {
  11.  
  12. std::string narrow(const std::wstring& wide, const std::locale& locale);
  13. std::wstring widen(const std::string& narrow, const std::locale& locale);
  14.  
  15. class any_string
  16. {
  17. public:
  18. explicit any_string(const char *, const std::locale& locale = std::locale("") );
  19. explicit any_string(const wchar_t *, const std::locale& locale = std::locale("") );
  20. explicit any_string(const std::string&, const std::locale& locale = std::locale("") );
  21. explicit any_string(const std::wstring&, const std::locale& locale = std::locale("") );
  22.  
  23. const std::string& str() const;
  24. const std::wstring& wstr() const;
  25.  
  26. operator const std::string&() const { return str(); }
  27. operator const std::wstring&() const { return wstr(); }
  28.  
  29. private:
  30. const std::locale m_locale;
  31. mutable std::tr1::shared_ptr<std::string> m_ansi;
  32. mutable std::tr1::shared_ptr<std::wstring> m_wide;
  33. };
  34.  
  35. class str_converter
  36. {
  37. public:
  38. str_converter(const std::locale& locale = std::locale("") );
  39.  
  40. any_string operator()(const char * str) { return any_string(str, m_locale); }
  41. any_string operator()(const wchar_t * str) { return any_string(str, m_locale); }
  42. any_string operator()(const std::string& str) { return any_string(str, m_locale); }
  43. any_string operator()(const std::wstring& str) { return any_string(str, m_locale); }
  44.  
  45. private:
  46. const std::locale m_locale;
  47. };
  48.  
  49. }} // namespace vr::str
  50. #endif // VR_STR_CONVERTER_HPP
  51.  
  52.  
  53.  
  54.  
  55. // str_convert.cpp:
  56.  
  57. #include "str_convert.hpp"
  58.  
  59. #include <stdexcept>
  60.  
  61. namespace vr { namespace str {
  62.  
  63. std::string narrow(const std::wstring& wide, const std::locale& locale)
  64. {
  65. if( wide.empty() )
  66. return std::string();
  67.  
  68. typedef std::wstring::traits_type::state_type state_type;
  69. typedef std::codecvt<wchar_t, char, state_type> CVT;
  70.  
  71. const CVT& cvt = std::use_facet<CVT>(locale);
  72. std::string narrow(cvt.max_length()*wide.size(), '\0');
  73. state_type state = state_type();
  74.  
  75. const wchar_t* from_beg = &wide[0];
  76. const wchar_t* from_end = from_beg + wide.size();
  77. const wchar_t* from_nxt;
  78. char* to_beg = &narrow[0];
  79. char* to_end = to_beg + narrow.size();
  80. char* to_nxt;
  81.  
  82. std::string::size_type sz = 0;
  83. std::codecvt_base::result r;
  84. do
  85. {
  86. r = cvt.out(state, from_beg, from_end, from_nxt,
  87. to_beg, to_end, to_nxt);
  88. switch (r)
  89. {
  90. case std::codecvt_base::error:
  91. throw std::runtime_error("Cannot convert wstring to string. Locale: "+locale.name());
  92.  
  93. case std::codecvt_base::partial:
  94. sz += to_nxt - to_beg;
  95. narrow.resize(2*narrow.size());
  96. to_beg = &narrow[sz];
  97. to_end = &narrow[0] + narrow.size();
  98. break;
  99.  
  100. case std::codecvt_base::noconv:
  101. narrow.resize(sz + (from_end-from_beg)*sizeof(wchar_t));
  102. std::memcpy(&narrow[sz], from_beg,(from_end-from_beg)*sizeof(wchar_t));
  103. r = std::codecvt_base::ok;
  104. break;
  105.  
  106. case std::codecvt_base::ok:
  107. sz += to_nxt - to_beg;
  108. narrow.resize(sz);
  109. break;
  110. }
  111. } while( r != std::codecvt_base::ok );
  112.  
  113. return narrow;
  114. }
  115.  
  116. std::wstring widen(const std::string& narrow, const std::locale& locale)
  117. {
  118. if( narrow.empty() )
  119. return std::wstring();
  120.  
  121. typedef std::string::traits_type::state_type state_type;
  122. typedef std::codecvt<wchar_t, char, state_type> CVT;
  123.  
  124. const CVT& cvt = std::use_facet<CVT>(locale);
  125. std::wstring wide(narrow.size(), '\0');
  126. state_type state = state_type();
  127. const char* from_beg = &narrow[0];
  128. const char* from_end = from_beg + narrow.size();
  129. const char* from_nxt;
  130. wchar_t* to_beg = &wide[0];
  131. wchar_t* to_end = to_beg + wide.size();
  132. wchar_t* to_nxt;
  133.  
  134. std::wstring::size_type sz = 0;
  135. std::codecvt_base::result r;
  136. do
  137. {
  138. r = cvt.in(state, from_beg, from_end, from_nxt,
  139. to_beg, to_end, to_nxt);
  140. switch (r)
  141. {
  142. case std::codecvt_base::error:
  143. throw std::runtime_error("Cannot convert string to wstring. Locale: "+locale.name());
  144.  
  145. case std::codecvt_base::partial:
  146. sz += to_nxt - to_beg;
  147. wide.resize(2*wide.size());
  148. to_beg = &wide[sz];
  149. to_end = &wide[0] + wide.size();
  150. break;
  151.  
  152. case std::codecvt_base::noconv:
  153. wide.resize(sz + (from_end-from_beg));
  154. std::memcpy(&wide[sz], from_beg, (std::size_t)(from_end-from_beg));
  155. r = std::codecvt_base::ok;
  156. break;
  157.  
  158. case std::codecvt_base::ok:
  159. sz += to_nxt - to_beg;
  160. wide.resize(sz);
  161. break;
  162. }
  163. } while( r != std::codecvt_base::ok );
  164.  
  165. return wide;
  166. }
  167. // --------------------------------------------------------------- any_string
  168. any_string::any_string(const char * str,const std::locale& locale) :
  169. m_locale(locale), m_ansi( new std::string(str) )
  170. {}
  171. any_string::any_string(const wchar_t * str,const std::locale& locale) :
  172. m_locale(locale), m_wide( new std::wstring(str) )
  173. {}
  174. any_string::any_string(const std::string& str,const std::locale& locale) :
  175. m_locale(locale), m_ansi( new std::string(str) )
  176. {}
  177. any_string::any_string(const std::wstring& str,const std::locale& locale) :
  178. m_locale(locale), m_wide( new std::wstring(str) )
  179. {}
  180.  
  181. const std::string& any_string::str() const
  182. {
  183. if( !m_ansi )
  184. {
  185. assert(m_wide);
  186.  
  187. m_ansi.reset( new std::string( narrow(*m_wide,m_locale) ) );
  188. }
  189.  
  190. return *m_ansi;
  191. }
  192. const std::wstring& any_string::wstr() const
  193. {
  194. if( !m_wide )
  195. {
  196. assert(m_ansi);
  197.  
  198. m_wide.reset( new std::wstring( widen(*m_ansi,m_locale) ) );
  199. }
  200.  
  201. return *m_wide;
  202. }
  203. // ------------------------------------------------------------ str_converter
  204. str_converter::str_converter(const std::locale& locale /*= std::locale("")*/ ) :
  205. m_locale(locale)
  206. {}
  207.  
  208. }} // namespace vr::str
  209.  
  210.  
  211. // *********************************************
  212. // Использовать примерно так:
  213.  
  214. #include "str_convert.hpp"
  215.  
  216. int main(int argc, char* argv[])
  217. {
  218. try
  219. {
  220. using namespace vr::str;
  221.  
  222. // wide -> ansi -> wide c использованием дефолтной локали
  223. const wchar_t * asdf = L"asdf";
  224. std::string ansi = any_string(asdf);
  225. std::wstring wide = any_string(ansi);
  226. if( wide != asdf )
  227. {
  228. std::cout<<"0 failed";
  229. }
  230.  
  231. // wide -> ansi -> wide c использованием русской локали
  232. std::locale russian("Russian");
  233. const wchar_t * hedgehog = L"ёж";
  234. std::string ansi1 = any_string(hedgehog, russian);
  235. std::wstring wide1 = any_string(ansi1, russian);
  236. if( hedgehog != wide1 )
  237. {
  238. std::cout<<"1 failed";
  239. }
  240.  
  241. // Если строк несколько, то проще так, чтобы локаль только один раз указывать:
  242. str_converter sc( std::locale("German_germany") );
  243. const wchar_t * message = L"\x00df - sharp-s";
  244. // wide -> ansi
  245. std::string str2 = sc(message);
  246. // wide -> wide :)
  247. std::wstring wstr2 = sc(message);
  248. // ansi -> wide
  249. std::wstring wstr21 = sc(str2);
  250.  
  251. if( wstr2 != wstr21 )
  252. {
  253. std::cout<<"2 failed";
  254. }
  255. }
  256. catch(std::exception& e)
  257. {
  258. std::cout << e.what();
  259. }
  260.  
  261. return 0;
  262. }
Надоела мне проблема c несоответствием std::string и std::wstring. К сожалению, иногда по историческим причинам() и из-за используемых библиотек приходится в одном проекте использовать и то, и то. Написал вот простенькие аналоги ATL::CW2A и компании. Код кроссплатформенный, проверен на Windows (VS2005), Debian(gcc 4.1.2) и Mac OS X (gcc 4.1.2 darwin port). Единственный тонкий момент — имена локалей на разных системах разные, надо учитывать (под *nix можно узнавать через locale -a).

http://www.rsdn.ru/Forum/message/3139273.1.aspx

+добавить реализацию