Преобразование u16string в float


У меня есть кодированная строка utf16, я хочу преобразовать ее в float

Например
Если есть формате UTF16 строку u"1342.223" он должен вернуть 1342.223 в поплавки, если он был в utf8 я использовал, чтобы преобразовать его с помощью stod функция, но как делать эту работу на формате UTF16 enocoded строку std::u16string

3 2

3 ответа:

Для этого нет стандартной функции. Если вы можете использовать std::wstring в системе, которая использует широкие символы 16bit, Вы можете использовать:

double d;
std::wistringstream(L"1342.223") >> d;
В противном случае вы можете воспользоваться простым преобразованием числовых цифр из UTF-16 в ASCII/UTF-8, чтобы написать функцию быстрого преобразования. Он не идеален, но должен быть достаточно эффективным:
double u16stod(std::u16string const& u16s)
{
    char buf[std::numeric_limits<double>::max_digits10 + 1];

    std::transform(std::begin(u16s), std::end(u16s), buf,
        [](char16_t c){ return char(c); });

    buf[u16s.size()] = '\0'; // terminator

    // some error checking here?
    return std::strtod(buf, NULL);
}

Во-первых, преобразование utf16 числовой символьной строки в узкую символьную строку является тривиальным. Даже если вы не можете быть уверены, что узкий набор символов является ASCII для 7-битных символов, C гарантирует, что код '0' - '9' будет последовательным, и это также верно для Unicode (0x30-0x39). Таким образом, код может быть таким же простым, как (зависит только от включения <string>:

double u16strtod(const std::u16string& u16) {
    char *beg = new char[u16.size() + 1];
    char *str = beg;
    for (char16_t uc: u16) {
        if (uc == u' ') *str++ = ' ';     // special processing for possible . and space
        else if (uc == u'.') *str++ = '.';
        else if ((uc < u'0') || (uc > u'9')) break;  // could use better error processing
        else {
            *str++ = '0' + (uc - u'0');
        }
    }
    *str++ = '\0';
    char *end;
    double d = strtod(beg, &end);   // could use better error processing
    delete[] beg;
    return d;
}    

Еще проще, если узкая кодировка-ASCII:

double u16strtod(const std::u16string& u16) {
    char *beg = new char[u16.size() + 1];
    char *str = beg;
    for (char16_t uc: u16) {
        if ((uc <= 0) || (uc >= 127)) break;  // can only contain ASCII characters
        else {
            *str++ = uc;      // and the unicode code IS the ASCII code
        }
    }
    *str++ = '\0';
    char *end;
    double d = strtod(beg, &end);
    delete[] beg;
    return d;
}

Если вы точно знаете, что ваша строка хорошо отформатирована (например, без пробелов), и тогда и только тогда, когда производительность критична (т. е. если вы разбираете миллионы или миллиарды чисел), не отвергайте возможность просто декодировать ее самостоятельно, циклически повторяя строку. Найдите исходный код стандартной библиотеки (возможно, сравните libc++ и libstdc++), чтобы увидеть, что они делают, и адаптируйте его. Конечно, в этих случаях вы также должны позаботиться о том, чтобы распараллелить свою работу, попытаться использовать SIMD и так далее.