конвертировать строку эмодзи в icu :: UnicodeString - PullRequest
0 голосов
/ 12 февраля 2020

У меня есть метод, который читает файл json и возвращает const char*, который может быть любым текстом, включая смайлики. У меня нет доступа к источнику этого метода.

Например, я создал файл json с флагом Англии, ??????? ({message: "\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67\uDB40\uDC7F"}).

Когда я вызываю этот метод, он возвращает что-то вроде í ¼í¿´í­€í±§í­€í±¢í­€í±¥í­€í±®í­€í±§í­€í±¿, но для его правильного использования мне нужно преобразовать его в icu :: UnicodeString, потому что я использую другой метод (снова с закрытым исходным кодом), который ожидает его.

Единственный способ заставить его работать - это что-то вроде:

icu::UnicodeString unicode;
unicode.setTo((UChar*)convertMessage().data());
std::string messageAsString;
unicode.toUTF8String(messageAsString);

, после этого messageAsString можно использовать и все работает.

convertMessage() - это метод который использует std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>::from_bytes(str).

Мой вопрос: есть ли способ создать icu::UnicodeString без использования этого дополнительного convertMessage() вызова?

1 Ответ

1 голос
/ 12 февраля 2020

Это пример использования функции ucnv_toUChars. Я взял эти функции из postgresql исходного кода и использовал его для своего проекта.

UConverter *icu_converter;

  static int32_t icu_to_uchar(UChar **buff_uchar, const char *buff, int32_t nbytes)
{
    UErrorCode  status;
    int32_t     len_uchar;

    status = U_ZERO_ERROR;
    len_uchar = ucnv_toUChars(icu_converter, NULL, 0,buff, nbytes, &status);
    if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR)
        return -1;

    *buff_uchar = (UChar *) malloc((len_uchar + 1) * sizeof(**buff_uchar));

    status = U_ZERO_ERROR;
    len_uchar = ucnv_toUChars(icu_converter, *buff_uchar, len_uchar + 1,buff, nbytes, &status);
    if (U_FAILURE(status))
        assert(0); //(errmsg("ucnv_toUChars failed: %s", u_errorName(status))));

    return len_uchar;
}
static int32_t icu_from_uchar(char **result, const UChar *buff_uchar, int32_t len_uchar)
{
    UErrorCode  status;
    int32_t     len_result;

    status = U_ZERO_ERROR;
    len_result = ucnv_fromUChars(icu_converter, NULL, 0,
        buff_uchar, len_uchar, &status);
    if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR)
        assert(0); // (errmsg("ucnv_fromUChars failed: %s", u_errorName(status))));

    *result = (char *) malloc(len_result + 1);

    status = U_ZERO_ERROR;
    len_result = ucnv_fromUChars(icu_converter, *result, len_result + 1,
        buff_uchar, len_uchar, &status);
    if (U_FAILURE(status))
        assert(0); // (errmsg("ucnv_fromUChars failed: %s", u_errorName(status))));

    return len_result;
}

void main() {

    const char *utf8String = "Hello";
    int len = 5;
    UErrorCode  status = U_ZERO_ERROR;

    icu_converter = ucnv_open("utf8", &status);
    assert(status <= U_ZERO_ERROR);

    UChar      *buff_uchar;
    int32_t len_uchar = icu_to_uchar(&buff_uchar, ut8String, len);

    // use buff_uchar

    free(buff_uchar);
}
...