C ++ 11, как преобразовать шестнадцатеричную строку в строку Unicode - PullRequest
1 голос
/ 21 марта 2019

Кажется, что даже с C ++ 11 это не так просто сделать, например,

string instring = "0x1234";  // hex string
string outstring = "ሴ"       // equivalent to "\u1234"

При условии, что у меня есть только шестнадцатеричное число в качестве входной строки, переданной из какого-то другого места, что означает, что я не знаю заранее шестнадцатеричное число. Какой лучший способ достичь этого?

Похоже, этот префикс '\ u' работает только тогда, когда сразу следует шестнадцатеричное число.

Идеи, которые я пытался и не работал:

1. std::regex_replace(instring, "0x", "\\u");
2. sprintf();

1 Ответ

2 голосов
/ 21 марта 2019

std::regex_replace не будет работать, так как работает с сохраненными фактическими данными. Символ "\\u" изменяет способ сохранения текста в данных. Простая замена не сработает - уже слишком поздно.

Вы могли бы немного поиграть с кодировкой. Я уверен, что для этого должна быть библиотека (я написал парсер , который берет необработанный файл UTF-8 и выводит кодовые точки многобайтовых символов, но на самом деле действительно ограничен по праву теперь плюс он не проверен должным образом ), но мы можем попытаться реализовать нашу собственную ограниченную версию, чтобы понять, что происходит внутри.

Прежде всего, почему UTF-8? На самом деле нет веских причин не делать этого. Это зависит от вашей локальной кодировки , но вы можете настроить ее под свои нужды.

Пример кода, написанного в редакторе UTF-8:

#include <iostream>
#include <string>
#include <bitset>

int main() {
    std::string str = "\u1234";
    for(char c : str) {
        std::cout << std::bitset<8>(static_cast<uint8_t>(c)) << ' ';
    }
}

будет производить 11100001 10001000 10110100.

Вы можете прочитать о std::bitset здесь . Если вы удивлены результатом (вы не знакомы с тем, как работает UTF-8), я призываю вас посмотреть отличное видео об этом.


Вернуться к теме. Цель состоит в том, чтобы вычислить значение hex , преобразовать его в последовательность байтов UTF-8 ( символов ) и сохранить в std::string.

псевдокод:

string := input;
hex := convertToHex(string);
sequence := hexToUTF8(hex);
output := seqToString(sequence); 

Мы предполагаем, что input будет предоставлено в виде шестнадцатеричной строки. Чтобы преобразовать шестнадцатеричную строку в десятичное значение, мы можем использовать std::stringstream:

std::string input = "0x1234";
std::stringstream stream{};
stream << std::hex << input;
int val;
stream >> val;

val будет равно 4660.

Теперь нам нужно построить последовательность байтов UTF-8, учитывая это значение. Мы можем использовать существующую библиотеку, std::wstring_convert, но , остерегайтесь , она считается устаревшей с C++17. Вам лучше использовать другую библиотеку , но мы будем придерживаться этой только для демонстрации примера:

#include <string>
#include <locale>
#include <codecvt>

int main()
{
    int val = 4660; // 0x1234
    std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter;
    std::string u8str = converter.to_bytes(val);
}

u8str теперь равно "\u1234".


Полный пример:

#include <cassert>
#include <codecvt>
#include <iostream>
#include <locale>
#include <sstream>
#include <string>

int hex_value(const std::string_view str) {
    std::stringstream stream{};
    stream << std::hex << str;
    int parsed;
    stream >> parsed;
    return parsed;
}

std::string map_to_utf8(const int val) {
    std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter;
    return converter.to_bytes(static_cast<char32_t>(val));
}

int main() {
    std::string input = "0x1234"; // read from file, let's assume...

    const auto value = hex_value(input);
    const auto str   = map_to_utf8(value);

    using namespace std::literals;
    assert(str == "\u1234"s && "\u1234"s == "ሴ"s); // passes
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...