在 C++ 中将字符串转换为 UTF-8
string to UTF-8 conversion in C++
我有一个字符串 Test\xc2\xae
,用十六进制表示为 0x54 0x65 0x73 0x74 0x5c 0x78 0x63 0x32 0x5c 0x78 0x61 0x65
。
该字符串中的字符集\xc2\xae
就是®(注册商标)的UTF-8编码。
我想编写一个 c++ 函数,它可以将 \xc2
(十六进制 0x5c 0x78 0x63 0x32
)字符集转换为十六进制值 0xc2
。
例如我想写一个 c++ 函数,它可以将 Test\xc2\xae
[0x54 0x65 0x73 0x74 0x5c 0x78 0x63 0x32 0x5c 0x78 0x61 0x65
] 转换为 Test®
[0x54 0x65 0x73 0x74 0xc2 0xae
]
据我了解您的问题,我认为您尝试将每个 \x??
序列(四个字符)(其中 ??
是两个十六进制数字的序列)转换为唯一的字符以十六进制表示的值。
如果您不必为此使用庞大的库,也许这个简单的算法可以解决问题。
/**
g++ -std=c++17 -o prog_cpp prog_cpp.cpp \
-pedantic -Wall -Wextra -Wconversion -Wno-sign-conversion \
-g -O0 -UNDEBUG -fsanitize=address,undefined
**/
#include <iostream>
#include <string>
#include <cctype>
std::string
convert_backslash_x(const std::string &str)
{
auto result=std::string{};
for(auto start=std::string::size_type{0};;)
{
const auto pos=str.find("\x", start);
if((pos==str.npos)|| // not found
(pos+4>size(str))) // too near from the end
{
// keep the remaining of the string
result.append(str, start);
break;
}
// keep everything until this position
result.append(str, start, pos-start);
const auto c1=std::tolower(str[pos+2]), c2=std::tolower(str[pos+3]);
if(std::isxdigit(c1)&&std::isxdigit(c2))
{
// convert two hex digits to a char with this value
const auto h1=std::isalpha(c1) ? 10+(c1-'a') : (c1-'0');
const auto h2=std::isalpha(c2) ? 10+(c2-'a') : (c2-'0');
result+=char(h1*16+h2);
// go on after this \x?? sequence
start=pos+4;
}
else
{
// keep this incomplete \x sequence as is
result+="\x";
// go on after this \x sequence
start=pos+2;
}
}
return result;
}
int
main()
{
for(const auto &s: {"Test\xc2\xae",
"Test\xc2\xae Test\xc2\xae",
"Test\xc2\xa",
"Test\x\xc2\xa"})
{
std::cout << '(' << s << ") --> (" << convert_backslash_x(s) << ")\n";
}
return 0;
}
我有一个字符串 Test\xc2\xae
,用十六进制表示为 0x54 0x65 0x73 0x74 0x5c 0x78 0x63 0x32 0x5c 0x78 0x61 0x65
。
该字符串中的字符集\xc2\xae
就是®(注册商标)的UTF-8编码。
我想编写一个 c++ 函数,它可以将 \xc2
(十六进制 0x5c 0x78 0x63 0x32
)字符集转换为十六进制值 0xc2
。
例如我想写一个 c++ 函数,它可以将 Test\xc2\xae
[0x54 0x65 0x73 0x74 0x5c 0x78 0x63 0x32 0x5c 0x78 0x61 0x65
] 转换为 Test®
[0x54 0x65 0x73 0x74 0xc2 0xae
]
据我了解您的问题,我认为您尝试将每个 \x??
序列(四个字符)(其中 ??
是两个十六进制数字的序列)转换为唯一的字符以十六进制表示的值。
如果您不必为此使用庞大的库,也许这个简单的算法可以解决问题。
/**
g++ -std=c++17 -o prog_cpp prog_cpp.cpp \
-pedantic -Wall -Wextra -Wconversion -Wno-sign-conversion \
-g -O0 -UNDEBUG -fsanitize=address,undefined
**/
#include <iostream>
#include <string>
#include <cctype>
std::string
convert_backslash_x(const std::string &str)
{
auto result=std::string{};
for(auto start=std::string::size_type{0};;)
{
const auto pos=str.find("\x", start);
if((pos==str.npos)|| // not found
(pos+4>size(str))) // too near from the end
{
// keep the remaining of the string
result.append(str, start);
break;
}
// keep everything until this position
result.append(str, start, pos-start);
const auto c1=std::tolower(str[pos+2]), c2=std::tolower(str[pos+3]);
if(std::isxdigit(c1)&&std::isxdigit(c2))
{
// convert two hex digits to a char with this value
const auto h1=std::isalpha(c1) ? 10+(c1-'a') : (c1-'0');
const auto h2=std::isalpha(c2) ? 10+(c2-'a') : (c2-'0');
result+=char(h1*16+h2);
// go on after this \x?? sequence
start=pos+4;
}
else
{
// keep this incomplete \x sequence as is
result+="\x";
// go on after this \x sequence
start=pos+2;
}
}
return result;
}
int
main()
{
for(const auto &s: {"Test\xc2\xae",
"Test\xc2\xae Test\xc2\xae",
"Test\xc2\xa",
"Test\x\xc2\xa"})
{
std::cout << '(' << s << ") --> (" << convert_backslash_x(s) << ")\n";
}
return 0;
}