c ++ 11如何将十六进制字符串转换为unicode字符串

时间:2019-03-20 23:34:16

标签: c++ c++11 unicode

似乎即使使用C ++ 11也不是一件容易的事,例如

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

假设我只有这个十六进制数字作为从其他位置传递过来的输入字符串,这意味着我事先不知道十六进制数字。实现此目标的最佳方法是什么?

看起来像这样的'\ u'前缀仅在紧随其后的十六进制数字时有效。

我尝试过但不起作用的想法:

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

1 个答案:

答案 0 :(得分:2)

std::regex_replace将不起作用,因为它可以处理存储的实际数据。 "\\u"字符更改文本在数据中的存储方式。仅仅替换它是行不通的-为时已晚。

可以播放一些编码。可以肯定的是,必须有一个库(我写了一个parser,它使用原始的UTF-8文件并输出多字节字符的代码点,但目前为止确实受限制) ,加上未经正确测试的),但是我们可以尝试实施自己的受限版本,以了解内部发生了什么。

首先,为什么选择UTF-8?确实没有充分的理由不这样做。这取决于您的local encoding,但是您可以根据需要进行调整。

用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 here的信息。如果您对结果感到惊讶(您不熟悉UTF-8的工作原理),建议您watch观看一段精彩的视频。


返回主题。目的是计算 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开始,它被视为已弃用。您最好使用different library,但我们将坚持使用该示例来演示示例:

#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
}