【问题标题】:How to check if a string has valid UTF-8 characters in C++?如何在 C++ 中检查字符串是否具有有效的 UTF-8 字符?
【发布时间】:2012-03-02 20:06:40
【问题描述】:

我正在尝试使用 ICU 库来测试字符串是否包含无效的 UTF-8 字符。我创建了一个 UTF-8 转换器,但没有无效数据给我一个转换错误。感谢您的帮助。

谢谢, 普拉桑特

int main()                                                                                        
{                                     
    string str ("AP1120 CorNet-IP v5.0 v5.0.1.22 òÀ MIB 1.5.3.50 Profile EN-C5000");
    //  string str ("example string here");
    //  string str (" ����������"     );                  
    UErrorCode status = U_ZERO_ERROR;                   
    UConverter *cnv;            
    const char *sourceLimit;    
    const char * source = str.c_str();                  
    cnv = ucnv_open("utf-8", &status);                                                              
    assert(U_SUCCESS(status));                                                                      

    UChar *target;                                                                                  
    int sourceLength = str.length();                                                                
    int targetLimit = 2 * sourceLength;                                                             
    target = new UChar[targetLimit];                                                                

    ucnv_toUChars(cnv, target, targetLimit, source, sourceLength, &status);
    cout << u_errorName(status) << endl;
    assert(U_SUCCESS(status));                          
}       

【问题讨论】:

  • 不熟悉这个库,但在我看来,如果你用"utf-8" 打开你的转换器,然后调用ucnv_toUChars 进行转换,你是不是或多或少地告诉它从Unicode 转换为Unicode?在这种情况下,它可能会成功短路。我会尝试使用 iso 编码或其他方式打开它。

标签: c++ utf-8


【解决方案1】:

我修改了你的程序以打印出实际的字符串,之前和之后:

#include <unicode/ucnv.h>
#include <string>
#include <iostream>
#include <cassert>
#include <cstdio>

int main()
{
    std::string str("22 òÀ MIB 1");
    UErrorCode status = U_ZERO_ERROR;
    UConverter * const cnv = ucnv_open("utf-8", &status);
    assert(U_SUCCESS(status));

    int targetLimit = 2 * str.size();
    UChar *target = new UChar[targetLimit];

    ucnv_toUChars(cnv, target, targetLimit, str.c_str(), -1, &status);

    for (unsigned int i = 0; i != targetLimit && target[i] != 0; ++i)
        std::printf("0x%04X ", target[i]);
    std::cout << std::endl;
    for (char c : str)
        std::printf("0x%02X ", static_cast<unsigned char>(c));
    std::cout << std::endl << "Status: " << status << std::endl;
}

现在,使用默认编译器设置,我得到:

0x0032 0x0032 0x0020 0x00F2 0x00C0 0x0020 0x004D 0x0049 0x0042 0x0020 0x0031
0x32 0x32 0x20 0xC3 0xB2 0xC3 0x80 0x20 0x4D 0x49 0x42 0x20 0x31

也就是说,输入已经是UTF-8了。这是我的编辑器将文件保存为 UTF-8(可在十六进制编辑器中验证)的阴谋,以及将 执行字符集 设置为 UTF-8 的 GCC。

您可以强制 GCC 更改这些参数。例如,强制执行字符集为 ISO-8859-1(通过-fexec-charset=iso-8859-1)会产生:

0x0032 0x0032 0x0020 0xFFFD 0xFFFD 0x0020 0x004D 0x0049 0x0042 0x0020 0x0031
0x32 0x32 0x20 0xF2 0xC0 0x20 0x4D 0x49 0x42 0x20 0x31

如您所见,输入现在是 ISO-8859-1 编码的,转换提示失败并产生“无效字符”代码点 U+FFFD。

但是,转换操作仍然返回“成功”状态。该库似乎没有将用户数据转换错误视为函数调用的错误。相反,错误状态似乎是为诸如空间不足之类的事情保留的。

【讨论】:

  • 有趣,当时我的猜测有点接近。 +1用于实验。我正要回来发帖说ucnv_getInvalidUChars 可能是 OP 想要的更多,但如果适用的话,你的答案可能会更好。
  • 感谢您的回答,现在可以理解为什么转换没有失败。出于测试目的,如果我想继续使用 gcc 的默认字符集,是否可以将输入保存为原始格式而不是 UTF-8 格式?
  • @user1245457:示例中没有输入,源代码中只有硬编码数据。实际的 input 没有任何反应,它只是一个不透明的字节流,您可以随意保存。
  • @KerrekSB - 如果我继续使用 gcc 的默认字符集,如何检测非 UTF8 输入?无论输入字符串如何,如果使用默认字符集,所有输入字符串都被标记为有效
  • 你没有。相反,您在手册中写道,“输入必须以 UTF-8 编码”。输入只是一系列愚蠢的数字,如果你不同意它们的含义,你就不能只是猜测。更好的解决方案是使用环境的语言环境设置(请参阅&lt;locale&gt;),然后执行整个mbsrtowcs- 然后是iconv-WCHAR 到UTF8 转换that I keep going on about...
猜你喜欢
  • 2013-08-16
  • 2016-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-03
  • 1970-01-01
  • 2017-01-25
相关资源
最近更新 更多