20

我知道 StackOverflow 上已经有几个关于std::stringvsstd::wstring或类似的问题,但没有一个提出完整的解决方案。

为了获得一个好的答案,我应该定义要求:

  • 多平台使用,必须在 Windows、OS X 和 Linux 上运行
  • 将平台特定的 Unicode 字符串(如CFStringRefwchar_t *char*UTF-8 或 OS API 所需的其他类型)转换为/从其转换的工作量最小。备注:我不需要代码页转换支持,因为我希望在所有支持的操作系统上只使用 Unicode 兼容函数。
  • 如果需要一个外部库,这个库应该是开源的,并且在一个非常自由的许可下,比如 BSD,而不是 LGPL。
  • 能够使用printf 格式语法或类似的语法。
  • 字符串分配/释放的简单方法
  • 性能不是很重要,因为我假设 Unicode 字符串仅用于应用程序 UI。
  • 一些例子将不胜感激

我真的很感激每个答案只有一个建议的解决方案,通过这样做,人们可以投票支持他们喜欢的替代方案。如果您有多个选择,只需添加另一个答案。

请指出对你有用的东西。

相关问题:

4

6 回答 6

7

我强烈建议在您的应用程序内部使用 UTF-8,使用常规旧的char*std::string用于数据存储。为了与使用不同编码(ASCII、UTF-16 等)的 API 交互,我建议使用在 LGPL 下获得许可的libiconv 。

示例用法:

class TempWstring
{
public:
  TempWstring(const char *str)
  {
    assert(sUTF8toUTF16 != (iconv_t)-1);
    size_t inBytesLeft = strlen(str);
    size_t outBytesLeft = 2 * (inBytesLeft + 1);  // worst case
    mStr = new char[outBytesLeft];
    char *outBuf = mStr;
    int result = iconv(sUTF8toUTF16, &str, &inBytesLeft, &outBuf, &outBytesLeft);
    assert(result == 0 && inBytesLeft == 0);
  }

  ~TempWstring()
  {
    delete [] mStr;
  }

  const wchar_t *Str() const { return (wchar_t *)mStr; }

  static void Init()
  {
    sUTF8toUTF16 = iconv_open("UTF-16LE", "UTF-8");
    assert(sUTF8toUTF16 != (iconv_t)-1);
  }

  static void Shutdown()
  {
    int err = iconv_close(sUTF8toUTF16);
    assert(err == 0);
  }

private:
  char *mStr;

  static iconv_t sUTF8toUTF16;
};

iconv_t TempWstring::sUTF8toUTF16 = (iconv_t)-1;

// At program startup:
TempWstring::Init();

// At program termination:
TempWstring::Shutdown();

// Now, to convert a UTF-8 string to a UTF-16 string, just do this:
TempWstring x("Entr\xc3\xa9""e");  // "Entrée"
const wchar_t *ws = x.Str();  // valid until x goes out of scope

// A less contrived example:
HWND hwnd = CreateWindowW(L"class name",
                          TempWstring("UTF-8 window title").Str(),
                          dwStyle, x, y, width, height, parent, menu, hInstance, lpParam);
于 2010-01-10T17:19:37.577 回答
5

与 Adam Rosenfield 的回答 (+1) 相同,但我使用的是 UTFCPP

于 2010-01-10T18:19:42.833 回答
3

我最近在一个项目中决定将 std::wstring 用于跨平台项目,因为“宽字符串是 Unicode,对吗?” 这导致了一些令人头疼的问题:

  • wstring 中的标量值有多大?答:这取决于编译器的实现。在 Visual Studio (Win) 中,它是 16 位。但在 Xcode (Mac) 中,它是 32 位的。
  • 这导致了一个不幸的决定,即使用 UTF-16 进行有线通信。但是哪个 UTF-16?有两种:UTF-16BE(大端)和 UTF16-LE(小端)。不清楚这一点会导致更多的错误。

当您使用特定于平台的代码时,使用平台的本机表示与其 API 进行通信是有意义的。但是对于跨平台共享或跨平台通信的任何代码,请避免所有歧义并使用 UTF-8。

于 2010-01-10T18:24:07.510 回答
1

我会在内存中使用 UTF16 表示,在硬盘或线路上使用 UTF-8 或 16。主要原因:UTF16 对每个“字母”都有固定的大小。这简化了处理字符串时的许多职责(搜索、替换零件,...)。

UTF-8 的唯一原因是减少了“西方/拉丁”字母的内存使用量。您可以将此表示用于磁盘存储或网络传输。它还有一个好处是您在加载/保存到磁盘/线路时不必担心字节顺序。

考虑到这些原因,我会在内部使用 std::wstring 或者 - 如果您的 GUI 库提供 Widestring,请使用它(如 QT 中的 QString)。对于磁盘存储,我会为平台 api 编写一个独立于平台的小型包装器。或者,如果他们有可用于此转换的平台无关代码,我会查看 unicode.org。


澄清:韩文/日文字母不是西方/拉丁文。日语是例如汉字。这就是我提到拉丁字符集的原因。


对于 UTF-16 不是 1 个字符/2 个字节。这个假设只适用于基本多语言平面上的字符(参见:http ://en.wikipedia.org/wiki/UTF16 )。大多数 UTF-16 用户仍然认为所有字符都在 BMP 上。如果您的应用程序无法保证这一点,您可以切换到 UTF32 或切换到 UTF8。

由于上述原因,许多 API(例如 Windows、QT、Java、.NET、wxWidgets)仍然使用 UTF-16

于 2010-01-11T08:02:25.897 回答
1

经验法则:使用原生平台 Unicode 形式进行处理(UTF-16 或 UTF-32),使用 UTF-8 进行数据交换(通信、存储)。

如果所有本机 API 都使用 UTF-16(例如在 Windows 中),则将字符串设为 UTF-8 意味着您必须将所有输入转换为 UTF-16,调用 Win API,然后将答案转换为 UTF-8。相当痛苦。

但如果主要问题是 UI,那么字符串就是简单的问题。更难的是UI框架。为此,我会推荐 wxWidgets ( http://www.wxWidgets.org )。支持许多平台,成熟(17 年并且仍然非常活跃),原生小部件,Unicode,自由许可证。

于 2010-01-11T07:13:00.770 回答
0

可以将 UTF-16 存储在std::string. 因此,原则上您可以std::string用于所有平台,并存储在平台首选的编码中(Linux 为 UTF-8,Windows 为 UTF-16 等)。这将使您在 C++ 类型级别上得到一些简单的东西,但必须跟踪字符串的编码。如果应用程序是独立的,这可能很简单,如果它必须互操作(参见存储,有线格式),则不太简单。

将 UTF-16 存储在其中的风险std::string在于,您迟早会调用.c_str(),结果将被解释为以第一个 0 结尾,即 forstd::string s = reinterpret_cast<char *>(L"hello")将在s[1].

于 2021-09-24T14:20:38.777 回答