【问题标题】:Size of UTF-8 string in bytesUTF-8 字符串的大小(以字节为单位)
【发布时间】:2011-06-17 02:49:01
【问题描述】:

我正在使用 QString 存储字符串,现在我需要将这些字符串(转换为 UTF-8 编码)存储在 POD 结构中,如下所示:

template < int N >
struct StringWrapper
{
  char theString[N];
};

要从 QString 转换原始数据,我这样做:

QString str1( "abc" );
StringWrapper< 20 > str2;
strcpy( str2.theString, str1.toUtf8().constData() );

现在是问题。我注意到,如果我从普通字符串转换,它工作正常:

QString str( "abc" );
std::cout<< std::string( str.toUtf8().constData() ) << std::endl;

将产生作为输出:

abc

但如果我使用一些特殊字符,例如:

QString str( "Schöne Grüße" );
std::cout<< std::string( str.toUtf8().constData() ) << std::endl;

我得到一个这样的垃圾:

Gr\xC3\x83\xC2\xBC\xC3\x83\xC2\x9F

我显然遗漏了一些东西,但究竟出了什么问题?


其他问题

UTF-8 编码字符的最大大小是多少?我读了 here 它是 4 个字节。

【问题讨论】:

    标签: c++ qt utf-8


    【解决方案1】:

    您需要回答的第一个问题是源文件的编码是什么? QString 默认构造函数假定它是 Latin1,除非你用 QTextStream::setCodecForCStrings() 改变它。因此,如果您的来源不是 Latin1(例如 UTF-8),那么此时您会得到错误的结果:

    QString str( "Schöne Grüße" );
    

    现在,如果您的源代码是 UTF-8,您需要将其替换为:

    QString str = QString::fromUtf8( "Schöne Grüße" );
    

    或者,更好的是,尽可能使用 QObject::trUf8(),因为它为您提供 i18n 功能作为免费奖励。

    接下来要检查的是控制台的编码是什么。您尝试向其打印 UTF-8 字符串,但它是否支持 UTF-8?如果它是 Windows 控制台,它可能不会。如果在具有某些 *.UTF-8 语言环境的 *nix 系统上使用 Unicode 字体与 xterm 兼容,那应该没问题。

    对您编辑的问题:

    我认为没有任何理由不信任 Wikipedia,尤其是当它涉及特定标准时。它还提到 UTF-8 过去最多有 6 个字节的字符。根据我的经验,使用合理的母语字符(如拉丁文/西里尔文/希伯来文/中文/日文)最多可以获得 3 个字节。 4 个字节可能用于更奇特的东西,如果你真的很好奇,可以随时查看标准。

    【讨论】:

    • QString str(L"Schöne Grüße");看起来更容易解决。
    • @MSalters,哇,这是我第一次听说宽字符串文字。尽管如此,不能保证在一般情况下使用任何特定的编码(以及它如何解释文字中的实际字节?),此外,QString 没有接受 wchar_t* 的构造函数,所以它会是QString str = QString::fromWCharArray(L"Schöne Grüße"); - 现在不太容易?
    • 嗯,按照 Trolltech 的标准,这非常愚蠢。至于“不保证编码”,至少wchar_t的编码在编译时是固定的,而不是依赖于语言环境。但是,是的,看起来像 #define QSTR(x) QString::fromWCharArray(L##x)
    • @MSalters,它在编译时是固定的,但你如何保证它是正确的?当然,编译器需要从您的源代码中的任何编码转换为 wchar_t(无论在特定平台上是什么)。问题是,它如何知道您的来源使用哪种编码?它可以使用本地编码,也可以尝试检测 UTF-8 或其他。再说一次,使用 QString() 或 QString::fromUtf8() 是 not 语言环境相关的。构造 QString 的唯一依赖于语言环境的方法是 QString::fromLocal8Bit(),您通常只想将其用于外部输入。
    • @SergeyTachenov:来自维基百科“原始规范涵盖最多 31 位的数字(通用字符集的原始限制)。2003 年 11 月,RFC 3629 将 UTF-8 限制为以 U+ 结尾10FFFF,以匹配 UTF-16 字符编码的约束。这删除了所有 5 和 6 字节序列,以及大约一半的 4 字节序列。"
    【解决方案2】:

    出错的第一件事是您陈述的假设。 QString 不存储 UTF-8,它存储 unicode 字符串。这就是您需要致电str1.toUtf8() 的原因。它会创建一个临时的 UTF-8 字符串。

    第二部分是 UTF-8 的工作原理。它是 ASCII 的多字节扩展。 üß 不是 ASCII 字符,您确实希望这两个字符都获得多字节表示。 std::cout 显然不期望 UTF-8。这取决于使用的std::locale

    【讨论】:

    • 好的,第一句修正了。谢谢
    • 关于第二部分,我希望得到一个垃圾而不是特殊字母
    • @VJo,你不能保证。例如,表示“ö”的字节之一可以被控制台终端解释为一个特殊的控制字符,意思是“将光标移动到行首”,因此下一个字符将覆盖前面的字符。或者更糟糕的事情,比如切换终端模式并使其完全无法使用。取决于使用的特定终端。
    猜你喜欢
    • 2013-04-26
    • 1970-01-01
    • 1970-01-01
    • 2015-09-01
    • 2013-02-06
    • 2012-02-01
    • 2011-09-08
    • 2019-07-30
    • 2012-01-20
    相关资源
    最近更新 更多