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
}