LINUX.ORG.RU

Преобразование std::string в std::wstring

 


0

2
$ cat test_encoding_conv.cpp 
#include <iostream>
#include <string>
#include <locale>
#include <codecvt>

int main() {
	std::string str = "z";
	std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
	std::wstring wstr = converter.from_bytes(str);
	std::string utf8 = converter.to_bytes(wstr);
	std::cout << utf8 << std::endl;
	return 0;
}
$ g++ -std=c++14 -o test_encoding_conv test_encoding_conv.cpp 
$ ./test_encoding_conv 
稀

Делал по примеру отсюда: http://stackoverflow.com/questions/7153935/how-to-convert-utf-8-stdstring-to-...

Почему не работает и печатает какой-то иероглиф вместо «z»?

РЕШЕНИЕ: Заменить std::codecvt_utf8_utf16 на std::codecvt_utf8. В результате всё отлично работает.

Как известно, на Linux wchar_t 32-битный, а под офтопиком - 16-битный. И судя по всему std::codecvt_utf8_utf16 неадекватно себя ведёт в этом случае. Соответственно, нужно либо гарантированно 16-битный тип, либо использовать другой преобразователь кодировку. Ответ на SO скорее всего тестировался под виндой, либо на другой версии libstdc++ (у кого-то всё работает, вероятно, баг имеет место быть не во всех версиях).

★★★★★

Последнее исправление: KivApple (всего исправлений: 2)

У меня все работает. С «привет»-ом вместо z тоже.

LANG="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_CTYPE="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_ALL=

Apple LLVM version 8.0.0 (clang-800.0.42.1)
staseg ★★★★★
()
#include <iostream>
#include <string>
#include <locale>
#include <codecvt>

int main() {
	std::string str = "z";
	std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
	std::wstring wstr = converter.from_bytes(str);
	std::string utf8 = converter.to_bytes(wstr);
	std::cout << utf8 << std::endl;
	return 0;
}

http://melpon.org/wandbox/permlink/g2rztJtNPFPZGoiH

Start
z
0
Finish
utf8nowhere ★★★
()
Ответ на: комментарий от staseg
$ clang -v
clang version 3.9.1 (tags/RELEASE_391/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-pc-linux-gnu/6.3.1
Found candidate GCC installation: /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/6.3.1
Found candidate GCC installation: /usr/lib/gcc/x86_64-pc-linux-gnu/6.3.1
Found candidate GCC installation: /usr/lib64/gcc/x86_64-pc-linux-gnu/6.3.1
Selected GCC installation: /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/6.3.1
Candidate multilib: .;@m64
Selected multilib: .;@m64
$ gcc -v
Используются внутренние спецификации.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/6.3.1/lto-wrapper
Целевая архитектура: x86_64-pc-linux-gnu
Параметры конфигурации: /build/gcc/src/gcc/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --enable-libmpx --with-system-zlib --with-isl --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object --enable-linker-build-id --enable-lto --enable-plugin --enable-install-libiberty --with-linker-hash-style=gnu --enable-gnu-indirect-function --disable-multilib --disable-werror --enable-checking=release
Модель многопоточности: posix
gcc версия 6.3.1 20170109 (GCC) 
$ echo $LANG
ru_RU.UTF-8
KivApple ★★★★★
() автор топика

Ничего не понятно

#include <codecvt>
#include <iostream>
#include <locale>
#include <string>


int main()
{
    std::string str = "z";
    std::wstring wstr;
    std::string utf8;

    std::wstring_convert<std::codecvt_utf8<wchar_t>> good_converter;
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> bad_converter;

    wstr = good_converter.from_bytes(str);
    utf8 = good_converter.to_bytes(wstr);
    for (size_t i = 0; i < wstr.length(); i++)
        printf("%#x    %#x\n", (int)wstr[i], utf8[i]);
   
    wstr = bad_converter.from_bytes(str);
    utf8 = bad_converter.to_bytes(wstr);
    for (size_t i = 0; i < wstr.length(); i++)
        printf("%#x    %#x\n", (int)wstr[i], utf8[i]);
}

Шланг говорит

0x7a    0x7a
0x7a    0x7a
Антилопа говорит
0x7a    0x7a
0x7a00    0xffffffe7

utf8nowhere ★★★
()

Мне кажется надо использовать либо std::codecvt_utf8<wchar_t>, либо std::codecvt_utf8_utf16<char16_t>. Первый конвертирует между мультибайтовым utf-8 и широкосимвольным ucs-4, всегда по одному широкому символу на юникодовский кодпоинт. Второй конвертирует между utf-8 и utf-16, по одному char16_t для кодпоинтов из basic multilingual plane, по два char16_t (суррогатная пара) для кодпоинтов из supplementary planes.

iliyap ★★★★★
()
Ответ на: комментарий от utf8nowhere

Видимо libstdc++ не тестировали codecvt_utf8_utf16, когда для представления utf-16 используется 32-разрядный тип. Попробуй с 16-разрядным типом.

Там в обе стороны неправильная конвертация. 7a00 должен давать 3-байтовый сиквенс.

iliyap ★★★★★
()
Ответ на: комментарий от iliyap

Верно. Замена codecvt_utf8_utf16 на codecvt_utf8 решила проблему - и одиночный символ z, и русские буквы конвертируются нормально теперь.

KivApple ★★★★★
() автор топика
Ответ на: комментарий от KivApple

Замена codecvt_utf8_utf16 на codecvt_utf8 решила проблему

Это из моего сообщения, второго в топике, было ясно.

utf8nowhere ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.