Преобразование одного символьного типа в другой

Я создаю функцию, которая меняет символ на нижний/верхний регистр. Однако я использую шаблоны, чтобы использовать любой тип char/wchar/char16_t/char32_t (char/wchar/char16_t/char32_t).

Моя проблема заключается в том, как преобразовать wchar_t/char16_t/char32_t в char, чтобы его можно было использовать проверять и преобразовывать с помощью std::islower(...) и std::tolower(...) и эквивалентной функции верхнего регистра, а затем замените их обратно на свой первоначальный тип char.

template<typename CharT>
CharT* UpperCase(CharT* str) {
    CharT* out;

    //Conversion goes here

    for(Uint i = 0; i < std::char_traits<CharT>::length(str); i++)
        std::strcat(string, str[i]);

    //Conversion goes here

    return out;
}
0
источник поделиться
1 ответ

std::islower() и std::tolower() работают с данными char выраженными в текущей локали. Существуют также функции std::iswlower() и std::towlower() которые работают с данными wchar_t вместо этого (обратите внимание, что они не поддерживают суррогаты UTF-16, хотя).

Вам нужно будет преобразовать ваши входные строки в wchar_t или локализованный char, выполнить ваши сравнения в нижнем регистре/преобразования по мере необходимости и затем преобразовать результат обратно в исходную кодировку по завершении.

Имейте в виду, что:

  • преобразования в/из локализованного char потенциально являются потерями для символов, отличных от ASCII, в зависимости от локали.

  • конверсии между char (только UTF-7/8) <-> wchar_t (UTF-16 или UTF-32, в зависимости от платформы) <-> char16_t (UTF-16) <-> char32_t (UTF-32) без потерь, поскольку все UTF представляют весь репертуар Unicode и специально предназначены для конверсий без потерь между собой.

Итак, чтобы свести к минимуму потерю данных, я бы предложил использовать std::iswlower()/std::towlower(), а затем создать несколько дополнительных шаблонов, которые помогут вам преобразовать ваши строки из CharT <-> wchar_t с помощью соответствующих преобразований. Вы можете использовать стандартные locale-независимые классы codecvt для codecvt char (только UTF-8)/char16_t/char32_t <-> wchar_t. Для преобразований char <-> wchar_t где локализуются данные char, вы можете использовать std::mbtowc()/std::mbrtowc() или locale-зависимые классы codecvt. Для обработки UTF-7 стандартных функций/классов нет, вам придется реализовать их вручную.

Например:

std::wstring toWString(const std::basic_string<char> &str)
{
    // if output is UTF-8, use std::codecvt_utf8 or std::codecvt_utf8_utf16 instead...
    std::wstring_convert<std::codecvt<wchar_t, char>> conv;
    return conv.from_bytes(str);
}

std::basic_string<char> fromWString(const std::wstring &str)
{
    // if output is UTF-8, use std::codecvt_utf8 or std::codecvt_utf8_utf16 instead...
    std::wstring_convert<std::codecvt<wchar_t, char>> conv;
    return conv.to_bytes(str);
}

std::wstring toWString(const std::basic_string<wchar_t> &str)
{
    return str;
}

std::basic_string<wchar_t> fromWString(const std::wstring &str)
{
    return str;
}

std::wstring toWString(const std::basic_string<char16_t> &str)
{
    std::wstring_convert<std::codecvt_utf16<char16_t>> conv;
    const char16_t *ptr = str.c_str();
    return conv.from_bytes( reinterpret_cast<const char*>(ptr), reinterpret_cast<const char*>(ptr + str.length()) );
}

std::basic_string<char16_t> fromWString(const std::wstring &str)
{
    std::wstring_convert<std::codecvt_utf16<char16_t>> conv;
    std::string tmp = conv.to_bytes(str);
    return std::u16string( reinterpret_cast<const char16_t*>(tmp.c_str()), tmp.length() * sizeof(char16_t) );
}

std::wstring toWString(const std::basic_string<char32_t> &str)
{
    std::wstring_convert<std::codecvt_utf16<char32_t>> conv;
    const char32_t *ptr = str.c_str();
    return conv.from_bytes( reinterpret_cast<const char*>(ptr), reinterpret_cast<const char*>(ptr + str.length()) );
}

std::basic_string<char32_t> fromWString(const std::wstring &str)
{
    std::wstring_convert<std::codecvt_utf16<char32_t>> conv;
    std::string tmp = conv.to_bytes(str);
    return std::u32string( reinterpret_cast<const char32_t*>(tmp.c_str()), tmp.length() * sizeof(char32_t) );
}

template<typename CharT>
std::basic_string<CharT> UpperCase(const std::basic_string<CharT> &str)
{
    std::wstring tmp = toWString(str);
    std::transform(tmp.begin(), tmp.end(), tmp.begin(), std::towlower);
    return fromWString(tmp);
}
+3
источник

Посмотрите другие вопросы по метке или Задайте вопрос