在unicode c ++中编写路径

时间:2016-02-11 01:19:03

标签: c++ unicode encoding utf-8

我在打开UTF-8路径文件时遇到了问题。具有UTF-8字符(如西里尔语或拉丁语)的路径。我找到了一种用_wfopen来解决这个问题的方法,但是当我用UTF手工编码UTF-8字符(\ Uxxxx)时解决它的方式。

是否有函数,宏或任何当我提供字符串(路径)时它将返回Unicode?

这样的事情: https://www.branah.com/unicode-converter

我尝试使用MultiByteToWideChar,但它会返回一些不相关的十六进制数字。

尝试:

std::wstring s2ws(const std::string& s)
{
    int len;
    int slength = (int)s.length() + 1;
    len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0);
    wchar_t* buf = new wchar_t[len];
    MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
    std::wstring r(buf);
    delete[] buf;
    return r;
}
std::wstring stemp = s2ws(x);
LPCWSTR result = stemp.c_str();

我得到的结果:0055F7E8

提前谢谢

更新

我安装了boost,现在我正在尝试使用boost。有人可以帮助我提升。

所以我有一条路: wchar_t path[100] = _T("čaćšžđ\\test.txt");

我需要将它转换为:

wchar_t s[100] = _T("\u010d\u0061\u0107\u0161\u017e\u0111\\test.txt");

3 个答案:

答案 0 :(得分:1)

这是一种在Windows上转换UTF-8和UTF-16的方法,以及显示输入和输出的存储代码单元的实际值:

#include <codecvt>
#include <iostream>
#include <iomanip>
#include <string>

int main() {
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> convert;

    std::string s = "test";

    std::cout << std::hex << std::setfill('0');
    std::cout << "Input `char` data: ";
    for (char c : s) {
      std::cout << std::setw(2) << static_cast<unsigned>(static_cast<unsigned char>(c)) << ' ';
    }
    std::cout << '\n';

    std::wstring ws = convert.from_bytes(s);

    std::cout << "Output `wchar_t` data: ";
    for (wchar_t wc : ws) {
      std::cout << std::setw(4) << static_cast<unsigned>(wc) << ' ';
    }
    std::cout << '\n';
}

了解输入和输出的实际值很重要,否则您可能无法正确理解您真正需要的转换。例如,在我看来,对于VC ++如何处理编码以及\Uxxxxxxxx\uxxxx在C ++源代码中实际执行的操作(例如,它们不一定产生UTF-)可能存在一些混淆。 8数据)。

尝试使用上面显示的代码来查看输入数据的真实含义。

强调我上面所写的内容;有强烈的迹象表明您可能无法正确理解输入上正在进行的处理,您需要对其进行彻底检查。

如果用以下内容替换测试字符串,上述程序会将ć(U + 0107)的UTF-8表示正确转换为单个16位代码单元0x0107

std::string s = "\xC4\x87"; // UTF-8 representation of U+0107

然后在Windows上使用Visual Studio输出程序:

  

输入char数据:c4 87
  输出wchar_t数据:0107

这与使用测试字符串形成对比,例如:

std::string s = "ć";

或者

std::string s = "\u0107";

这可能会导致以下输出:

  

输入char数据:3f
  输出wchar_t数据:003f

这里的问题是Visual Studio不使用UTF-8作为字符串的编码而没有一些技巧,所以你从UTF-8转换的请求可能不是你真正需要的;或者您确实需要从UTF-8转换,但是您正在使用与实际输入不同的输入来测试潜在的转换例程。

  

所以我有一条路径:wchar_t path [100] = _T(“čaćšžđ\ test.txt”);

     

我需要将它转换为:

     

wchar_t s [100] = _T(“\ u010d \ u0061 \ u0107 \ u016​​1 \ u017e \ u0111 \ test.txt”);

好的,如果我理解正确,你的实际问题是以下失败:

wchar_t path[100] = _T("čaćšžđ\\test.txt");
FILE *f = _wfopen(path, L"w");

但是如果你改写字符串就像:

wchar_t path[100] = _T("\u010d\u0061\u0107\u0161\u017e\u0111\\test.txt");

然后_wfopen调用成功并打开您想要的文件。

首先,这与UTF-8完全无关。我假设您找到了一些使用char字符串并将其转换为wchar_t的解决方法,并且您以某种方式将其解释为涉及UTF-8或其他内容。

您使用哪种编码保存源代码?字符串L"čaćšžđ\\test.txt"实际上是否正确保存?尝试关闭源文件并重新打开它。如果某些字符显示为?,则部分问题是源文件编码。特别是Windows在大多数北美和西欧使用的默认编码都是如此:“西欧(Windows) - 代码页1252”。

您还可以检查以下程序的输出:

#include <iomanip>
#include <iostream>

int main() {
    wchar_t path[16] = L"čaćšžđ\\test.txt";

    std::cout << std::hex << std::setfill('0');
    for (wchar_t wc : path) {
        std::cout << std::setw(4) << static_cast<unsigned>(wc) << ' ';
    }
    std::cout << '\n';
    wchar_t s[16] = L"\u010d\u0061\u0107\u0161\u017e\u0111\\test.txt";

    for (wchar_t wc : s) {
        std::cout << std::setw(4) << static_cast<unsigned>(wc) << ' ';
    }
    std::cout << '\n';
}

您需要了解的另一件事是\uxxxx写字符形式(称为通用字符名称或UCN)不是可以在C ++中将字符串转换为字符串的表单。当您编译程序并且它正在运行时,即当您编写的任何代码可能正在尝试生成包含\uxxxx的字符串时,编译器将UCN解释为不同字符的时间早已过去。唯一可行的UCN是直接写在源文件中的。

另外,您错误地使用了_T()。 IMO您根本不应该使用TCHAR和相关的宏,但是如果您确实使用它,那么您应该始终如一地使用它:不要混淆TCHAR API并明确使用* W API或wchar_tTCHAR的重点是允许代码独立并在wchar_t和Microsoft的“ANSI”API之间切换,因此使用TCHAR然后硬编码{{1}的假设} TCHAR击败了整个目的。

你应该写:

wchar_t

答案 1 :(得分:0)

问题是我将CPP文件保存为ANSI ...我必须将其转换为UTF-8。我在发布之前试过这个,但是VS 2015把它变成了ANSI,我不得不在VS中改变它,所以我可以让它工作。

我尝试用notepad ++打开cpp文件并更改编码但是当我打开VS时它会自动返回。所以我期待Save As选项,但没有编码选项。最后我在Visual Studio 2015中找到了它

文件 - &gt; “编码”下拉列表中的“高级保存选项”将其更改为Unicode

enter image description here

有一点对我来说仍然很奇怪,VS是如何正常显示字符的,但当我在N ++中打开文件时,有(因为它应该是因为ANSI)?

答案 2 :(得分:0)

您的代码是特定于Windows的,并且您使用的是Visual C ++。所以,只需使用宽文字。 Visual C ++支持文件流构造函数的宽字符串。

就这么简单 - 当你不需要携带时。

#include <fstream>
#include <iostream>
#include <stdlib.h>
using namespace std;

auto main() -> int
{
    wchar_t const path[] = L"cacšžd/test.txt";
    ifstream f( path );
    int ch;
    while( (ch = f.get()) != EOF )
    {
        cout.put( ch );
    }
}

但请注意,此代码是特定于Visual C ++的。这对于特定于Windows的代码来说是合理的。可能使用C ++ 17,我们将Boost文件系统库采用到标准库中,然后为了符合性,g ++将理想地提供此处使用的构造函数。