2012-03-02 3 views
2

Я пытаюсь использовать библиотеки ICU для проверки, имеет ли строка недопустимые символы UTF-8. Я создал конвертер utf-8, но никакие недопустимые данные не дают мне ошибку при преобразовании. Ценю вашу помощь.C++ проверить, имеет ли строка действительные символы utf-8

Спасибо, Prashanth

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

ответ

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 (проверяемый в шестнадцатеричном редакторе) и GCC, который устанавливает набор символов выполнения в UTF-8.

Вы можете принудить 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 кодировке, и преобразование prompty не работает и создает кодовые точки «недопустимый символ» U + FFFD.

Однако операция преобразования по-прежнему возвращает состояние «успешного». Похоже, что библиотека не считает ошибку преобразования пользовательских данных ошибкой вызова функции. Скорее, состояние ошибки, похоже, зарезервировано для таких вещей, как нехватка места.

+0

Интересно, моя догадка была несколько близка. +1 для экспериментов. Я собирался вернуться с сообщением, что 'ucnv_getInvalidUChars' может быть больше того, чего хочет OP, но может быть лучше в вашем ответе, если это применимо. – AJG85

+0

Спасибо за ваш ответ, теперь имеет смысл, почему преобразование не терпит неудачу. Для целей тестирования, если я хочу продолжать использовать набор символов gcc по умолчанию, можно ли сохранить ввод таким образом, чтобы он сохранялся в исходной форме, а не в форме UTF-8? – user1245457

+0

@ user1245457: В примере нет ввода, а в исходном коде - только жестко заданные данные. Ничего не происходит с фактическим * входом *, который является просто непрозрачным байтовым потоком и который вы можете сохранить по своему усмотрению. –

Смежные вопросы