在std::string中存储非英文字符串

7

我有一个简单的字符串在std::wstring中。

std::wstring tempStr = _T("F:\\Projects\\Current_자동_\\Cam.xml");

我想将这个字符串存储到一个 std::string 中。

我已经尝试了以下代码,但结果与输入的字符串不同。

std::wstring tempStr = _T("F:\\Projects\\Current_자동_\\Cam.xml");
//setup converter
typedef  std::codecvt_utf8_utf16 <wchar_t> convert_type;
std::wstring_convert<convert_type, wchar_t> converter;

//use converter (.to_bytes: wstr->str, .from_bytes: str->wstr)
std::string converted_str = converter.to_bytes( tempStr );

输入字符串中的韩文字符串被转换为"ìžë™"。有没有办法将相同的字符串转换为std::string?期望结果: converted_str应该包含F:\Projects\Current_자동_\Cam.xml。以下是调试截图,显示了3种情况下的3个值(以3种方式进行转换),但没有一个给出所需的值。

4
由于问题实际上是关于打开文件的,因此您应该展示打开文件的代码。那就是需要更改的地方,因为它获取的编码方式与预期不同。 - Steve Jessop
@Narendra:您使用的编码必须与您使用的文件打开函数所期望的编码匹配。 - Cheers and hth. - Alf
1
Visual Studio的调试器没有正确打印字符串。这并不意味着字符串没有被正确转换。就像@Cheersandhth.-Alf所说,我认为你应该看看你正在尝试使用的文件打开函数,而不要关注调试器认为字符串的含义。 - user2675345
你需要了解编码的工作原理。当字符集存储在字符串或文件中时,它会被编码成字节。对于ASCII字符来说,这是一个简单的转换,其中一个字符变成一个字节。但由于其他字符集(如Unicode)具有超过256个字符,因此每个字符需要多个字节。查看编码字节最可靠的方法是打印它们的十六进制值,就像本页上的其他人所做的那样。这是因为如果你要求Visual Studio为你打印字符串的内容,它不会知道它是一个Unicode字符串,也不知道如何解码它。 - flup
即使将字符串打印到标准输出,你在终端上看到的内容也取决于操作系统的设置。如果你通过ssh终端观看,则取决于客户端操作系统的设置、ssh终端软件的设置以及远程系统的操作系统设置。当你将代码提交到版本控制时,同样会遇到这个问题。编码是复杂的。或者说是混乱的... - flup
显示剩余6条评论
5个回答

4
你的转换代码很好。
事实上,在UTF-8中(即你存储在std :: string中的字符串),字符“自动”对应于:
자 (UTF-16 0xC790) ---> UTF-8:  EC 9E 90
동 (UTF-16 0xB3D9) ---> UTF-8:  EB 8F 99
如果你运行以下程序,只是打印转换后的UTF-8字节,你会得到这个输出:
ec 9e 90 eb 8f 99

#include <iomanip>      // For std::hex
#include <iostream>     // For console output
#include <string>       // For STL strings
#include <codecvt>      // For Unicode conversions

void print_char_hex(const char ch)
{
    auto * p = reinterpret_cast<const unsigned char*>(&ch);
    int i = *p;
    std::cout << std::hex << i << ' ';
}

int main()
{
    std::wstring utf16_str = L"\xC790\xB3D9";

    // setup converter
    typedef  std::codecvt_utf8_utf16<wchar_t> convert_type;
    std::wstring_convert<convert_type, wchar_t> converter;

    // use converter (.to_bytes: wstr->str, .from_bytes: str->wstr)
    std::string converted_str = converter.to_bytes( utf16_str );

    // Output the converted bytes (UTF-8)
    for (size_t i = 0; i < converted_str.length(); ++i)
    {
        print_char_hex(converted_str[i]);
    }
    std::cout << std::endl;
}

我使用 utf16_str = "F:\Projects\Current_자동_\Cam.xml" 运行了这段代码,但是输出中没有出现“自动”这个词。 - Narendra
正如您所看到的,我输入了您使用的韩文字符的相应UTF-16编码。我倾向于在C++源代码中使用纯ASCII。如果您想直接在源代码中输入韩文字符,您可以尝试使用UTF-16编码保存源文件。 - Mr.C64

0

我认为最好的解决方案是使用宽字符API打开文件,例如CreateFileW(...);,因为这样你可以直接使用宽字符文件名。

如果不可能的话,也许字符串不应该转换为UTF8,而是转换为系统默认的ANSI代码页。 我认为这可能会起作用:

    char out[200];
    wchar_t * in = L"F:\\Projects\\Current_자동_\\Cam.xml";
    WideCharToMultiByte(CP_ACP, 0, in, 100, out, 100, 0, 0);

或者可能是另一个韩国代码页:

    WideCharToMultiByte(949, 0, in, 100, out, 100, 0, 0);
    WideCharToMultiByte(1361, 0, in, 100, out, 100, 0, 0);
    WideCharToMultiByte(10003, 0, in, 100, out, 100, 0, 0);
    WideCharToMultiByte(20833, 0, in, 100, out, 100, 0, 0);
    WideCharToMultiByte(20949, 0, in, 100, out, 100, 0, 0);
    WideCharToMultiByte(50225, 0, in, 100, out, 100, 0, 0);
    WideCharToMultiByte(50933, 0, in, 100, out, 100, 0, 0);
    WideCharToMultiByte(51949, 0, in, 100, out, 100, 0, 0);

这里可以找到代码页 ID: http://msdn.microsoft.com/en-us/library/windows/desktop/dd317756(v=vs.85).aspx

祝你好运 :-)


0

这是有效的。你可以知道,因为转换回UTF16是有效的。如果你将UTF8字符串写入文件,它也会正确显示。这样,现在你有两种验证它有效的方法。

// UTF16ToUTF8.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>
#include <iostream>
#include <codecvt>

std::wstring ToUTF16(const std::string &data)
{
    return std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(data);
}

std::string ToUTF8(const std::wstring &data)
{
    return std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(data);
}

int _tmain(int argc, _TCHAR* argv[])
{
    std::wstring u16 = L"_자동_";
    std::string u8 = ToUTF8(u16);

    MessageBoxW(NULL, ToUTF16(u8).c_str(), L"", 0);

    std::cin.get();
    return 0;
}

0

你可以把UTF-8存储在std:string中,就像普通的字符序列一样。这里有一些有用的库,例如length()和关于索引的所有内容,你可能想要使用http://utfcpp.sourceforge.net/

对于Windows控制台,您需要将代码页设置为65001,并将其变成UTF-8。

不幸的是或者不是,std::wstring和整个wchar_t事物都没有指定任何特定的编码。

顺便说一下,如果你正在使用Managed C++,为什么不使用.NET Framework的System::String^?根本没有任何编码问题。http://msdn.microsoft.com/ru-ru/library/system.string(v=vs.110).aspx?cs-save-lang=1&cs-lang=cpp


-1
问题不在于您的字符串转换代码。这是一个典型的源文件编码问题。Visual Studio默认不使用Unicode,因此您应该自己将源文件的编码转换为UTF-8。要进行此转换,您可以使用notepad++打开文件,然后单击“编码”->“转换为UTF-8”。
注意1:在VS2010和vs2012中,如果您向源文件写入非ASCII字符,Visual Studio现在会发出警告并提供进行此转换的选项。
注意2:从您使用宏_T()的方式来看,我预测这只针对Windows。如果您尝试构建包含BOM的UTF-8编码源文件,并使用gcc,则可能会出现不同的错误。无论如何,最好的方法是在运行时从文件中读取UTF-8编码的文本数据。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接