2012-03-02 31 views
2

我想使用ICU库来测试,如果一个字符串具有无效的UTF-8字符。我创建了一个utf-8转换器,但没有无效的数据给我转换错误。感谢你的帮助。C++检查,如果字符串具有有效的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));       
}         
+0

不熟悉这个库,但在我看来,如果你用'“utf-8”'打开你的转换器,然后调用'ucnv_toUChars'进行转换,是不是你或多或少告诉它将Unicode转换为Unicode?在这种情况下,它可能会成功短路。我会尝试用iso编码或其他东西打开它。 – AJG85 2012-03-02 20:14:21

回答

4

我修改你的程序打印出实际的字符串,前后:现在

#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更改这些参数。例如,强制执行字符(通过-fexec-charset=iso-8859-1)设置为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编码,并且转换prompty 失败并产生“无效字符”码点U + FFFD。

但是,转换操作仍返回“成功”状态。看起来库不考虑用户数据转换错误是函数调用的错误。相反,错误状态似乎仅用于空间不足等情况。

+0

有趣的是,我的猜测有点接近。 +1进行实验。我正要回来发帖说ucnv_getInvalidUChars可能更适合OP,但如果适用的话,您的回答可能会更好。 – AJG85 2012-03-02 21:05:11

+0

感谢您的回答,现在有道理,为什么转换没有失败。出于测试目的,如果我想继续使用默认的gcc字符集,是否可以将输入保存为原始格式而不是UTF-8格式? – user1245457 2012-03-05 21:51:18

+0

@ user1245457:示例中没有输入,只有源代码中的硬编码数据。实际*输入*没有任何反应,它只是一个不透明的字节流,您可以随意保存。 – 2012-03-05 21:57:31