【发布时间】:2021-08-14 22:08:15
【问题描述】:
我想在使用 wxWidgets 3.1 的跨平台应用程序中处理文件。我依赖一些只接受文件名作为std::string 的函数。
在 Windows 上,我可以简单地使用 wxString::ToStdString(),一切都很好。
在 Linux (Ubuntu 20.04 LTS) 上,当文件名或路径中包含“特殊”字符(例如,法语 Ubuntu“Téléchargement”上的默认下载目录)时,转换失败并返回一个空字符串。
当我在 Linux 上明确指定以下转换器时,转换成功:std::string str = wxs.ToStdString(wxMBConvUTF8());
但这在 Windows 上不起作用,并且会打乱“特殊”字符。
我想,我可以编写依赖于平台的代码来处理这个问题,但这违背了工具包的目的。
我对此做了很多研究,但我现在完全糊涂了。我认为wxString 在 Unicode wxWidgets 构建(我正在使用)中使用 std::string?为什么这(显然)依赖于平台?我错过了什么?
这是一个最小的例子,它会弹出三个消息框:第一个正确显示wxString,第二个显示没有字符串(因为转换失败),第三个显示转换完成后的字符串.在 Windows 上,前两个框正确显示字符串,最后一个框显示两个 'é' 的错误字符。
#include "wx/wx.h"
#include <fstream>
class MyApp : public wxApp
{
public:
virtual bool OnInit() wxOVERRIDE;
};
class MyFrame : public wxFrame
{
public:
MyFrame(const wxString& title);
private:
};
wxIMPLEMENT_APP(MyApp);
bool MyApp::OnInit()
{
if (!wxApp::OnInit())
return false;
// create the main application window
MyFrame* frame = new MyFrame("Minimal wxWidgets App");
frame->Show(true);
return true;
}
// Some file I/O function
std::string openFile(std::string fileName)
{
std::ifstream file(fileName);
if (file)
{
return "Success!";
}
else
{
return "Failure!";
}
}
// frame constructor
MyFrame::MyFrame(const wxString& title)
: wxFrame(NULL, wxID_ANY, title)
{
wxString name = wxFileSelector("Pick a file"); // Pick a file with a "special" character in the name, e.g. Äréa.txt
wxMessageBox(openFile(name.ToStdString())); // Success! on Windows; Failure! on Linux
wxMessageBox(openFile(std::string(name.ToUTF8()))); // Failure! on Windows; Success! on Linux
}
编辑: 我发现 wxWidgets(在 3.1.5 中)最近添加了这个:
Add wxString::utf8_string() 这又增加了一个转换 函数,虽然不理想,但还是比不得不写的好 ToStdString(wxConvUTF8) 每次无损转换 wxString to std::string: 这不仅太长,而且太容易 忘记指定wxConvUTF8,导致使用时数据丢失 非 UTF-8 语言环境。
所以你会认为这可以解决问题。但是我 am 使用的是 UTF-8 语言环境!这是locale 命令的输出:
LANG=en_US.UTF-8
LANGUAGE=
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC=de_DE.UTF-8
LC_TIME=de_DE.UTF-8
LC_COLLATE="en_US.UTF-8"
LC_MONETARY=de_DE.UTF-8
LC_MESSAGES="en_US.UTF-8"
LC_PAPER=de_DE.UTF-8
LC_NAME=de_DE.UTF-8
LC_ADDRESS=de_DE.UTF-8
LC_TELEPHONE=de_DE.UTF-8
LC_MEASUREMENT=de_DE.UTF-8
LC_IDENTIFICATION=de_DE.UTF-8
LC_ALL=
EDIT2:我将最小示例更改为更接近我实际尝试做的事情。
EDIT3:我将示例更改为甚至更接近我实际尝试做的事情。 :-)
【问题讨论】:
-
可以改一下函数实现吗?我可能会尝试使用 std::wstring 来代替......如果做不到这一点 - 我可能会编写依赖于平台的代码。您所依赖的函数不支持 UNICODE。
-
但是std::string可以处理UTF-8,这里应该够用了。我认为这就是它在 Windows 上运行的原因。为什么它不能在 Linux 上运行?
-
我也认为
std::string str = wxs.utf8_str();应该适用于所有平台。你能看看这是否有效吗? -
@Simon,你确定是 UTF-8 吗?记住 Windows 原生字符串是 UTF-16...
-
确实如此,但 STL 字符串仍然是 UTF-8 并且应该是可移植的:docs.microsoft.com/en-us/archive/msdn-magazine/2016/september/…
标签: c++ unicode wxwidgets stdstring