【问题标题】:Preserve non-ascii characters between std::string and QString在 std::string 和 QString 之间保留非 ascii 字符
【发布时间】:2014-11-04 16:59:03
【问题描述】:

在我的程序中,用户可以在命令行上提供文件名或使用QFileDialog。在第一种情况下,我有一个没有任何编码信息的char*,在第二种情况下,我有一个QString

为了存储文件名供以后使用(最近的文件),我需要它作为QString。但是要使用std::ifstream 打开文件,我需要std::string

现在乐趣开始了。我能做到:

filename = QString::fromLocal8Bit(argv[1]);

稍后,我可以做到:

std::string fn = filename.toLocal8Bit().constData();

这适用于大多数角色,但不是全部。例如,单词Раи́са 在经过这种转换后看起来是一样的,但实际上有不同的字符。 所以虽然我可以有一个Раи́са.txt,它会显示Раи́са.txt,但它不会在文件系统中找到该文件。大多数字母都有效,但 и́ 无效。 (请注意,在QFileDialog 中选择文件时,它确实可以正常工作。当它来自命令行时,它不会。)

有没有更好的方法来保存文件名?现在我以任何本机编码获得它,并且可以在不知道它的情况下以相同的编码传递。至少我是这么认为的。

【问题讨论】:

  • 为什么使用ifstream打开文件,而不是QFile?
  • 文件在没有 Qt 依赖的不同模块中打开。它与 GUI 分离。
  • 你为什么使用 QString::fromLocal8Bit ?从这个函数的文档中它说:“QTextCodec::codecForLocale() 用于执行从 Unicode 的转换。如果无法确定语言环境编码,则此函数与 toLatin1() 相同。”看起来在您的情况下 toLatin1() 最终被调用,当您稍后调用 toLocal8Bit() 时发生以下情况:“如果此字符串包含任何无法在语言环境中编码的字符,则返回的字节数组是未定义的。这些字符可能会被抑制或被另一个替换。”
  • 如果您使用的是 Qt5,您是否尝试过 QString filename(argv[1]);后来只是 std::string fn = QByteArray(filename).constData();
  • @N1ghtLight 我也有同样的想法,但是他QString filename 中看到了正确的字符串,所以他的codecForLocale 必须正确设置,因为如果toLatin1 得到称为特殊字符的有:“用问号抑制或替换”。 qt-project.org/doc/qt-5/qstring.html#toLatin1

标签: qt character-encoding qstring


【解决方案1】:

'и́' 不是 ASCII 字符,也就是说它没有 8 位表示。它在argv[1] 中的表示方式取决于操作系统。但它并没有在一个 char 中得到体现。

fromLocal8bit 使用与toLocal8bit 相同的QTextCodec::codecForLocale。正如你所说,你的std::string 将持有“Раи́са.txt”,所以这不是问题。

取决于您的操作系统如何定义std::ifstream,尽管std::ifstream 可能期望每个char 都是它自己的char,而不是经过操作系统的翻译。我希望你在 Windows 上,因为你看到了这个问题。在这种情况下,您应该使用 std::fstreamstd::wstring 实现,这是 Microsoft 特定的:http://msdn.microsoft.com/en-us/library/4dx08bh4.aspx

您可以使用toStdWStringQString 获取std::wstring

查看这里了解更多信息:fstream::open() Unicode or Non-Ascii characters don't work (with std::ios::out) on Windows

编辑:

对于可以访问它的项目来说,一个很好的跨平台选项是Boost::Filesystemypnos 提到 File-Streams 是特别相关的。

【讨论】:

  • 其实它是跨平台的,我在Linux上测试过。这就是为什么我现在放弃 wstring..
  • @ypnos 我不是 Linux 专业人士,但我知道它使用 UTF-8 作为文件系统。因此,您可能希望在 Windows 上使用 std::wstring 和在 Linux 上使用 QString::toUtf8 来使用 #ifdef。更清洁的替代方法是使用 Boost:Filesystem 但我理解回避这一点。
  • 这是个好建议。在 Linux 上,您现在大多使用 UTF8,但只是大部分。然后还有 OS X。Boost:Filesystem 是个好主意。根据您的建议,我找到了boost.org/doc/libs/1_47_0/libs/filesystem/v3/doc/…
  • @ypnos 是的,最棒的是我相信所有基于path 的东西都在 tr2 中,所以它应该进入下一次重大的 C++ 更新。因此,与其学习一些你永远不会再使用的东西,不如学习 C++ 的未来!
  • 哈哈,这是一个很好的 Boost 广告。我什至在我的项目中已经有一个 Boost:Filesystem 依赖项,所以我正在认真考虑它。
猜你喜欢
  • 2018-05-18
  • 1970-01-01
  • 2014-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-02
  • 2011-10-07
相关资源
最近更新 更多