如何以数值形式遍历字符串字节?Windows-1256转UTF-8场景
问题描述
我有一个以Windows-1256编码的字符串,显示为ÓíÞÑÕäí áßí ¿,在配置对应编码的系统上应显示为阿拉伯文。我想手动将其转换为UTF-8,需要遍历字符串的每个字节查看二进制值,但遇到以下问题:
- 字符串显示13个可见字符,遍历循环却执行了24次(推测被错误识别为UTF-8或UTF-16)
- 获取字节数值时出现异常:负数、超大数值、乱码输出
以下是我的C++代码及输出结果:
#include <iostream> #include <bitset> using std::string; using std::cout; using std::endl; int main() { string myString = "ÓíÞÑÕäí áßí ¿"; // 该文本应为Windows-1256编码 cout << "string is : " << myString << endl; // 输出: string is : ÓíÞÑÕäí áßí ¿ cout << "length : " << myString.size() << endl; // 输出: length : 24 for (std::size_t i = 0; i < myString.size(); ++i) { uint8_t b1 = (uint8_t)myString.c_str()[i]; unsigned char b2 = (unsigned char) myString.c_str()[i]; unsigned int b3 = (unsigned int) myString.c_str()[i]; int b4 = (int) myString.c_str()[i]; cout << i << " - " << std::bitset<8>(myString.c_str()[i]) << " : " << b1 // 打印� << " : " << b2 // 打印� << " : " << b3 // 打印超大数值,空格除外(32) << " : " << b4 // 打印负数,空格除外(32) << endl; } return 0; }
输出
string is : ÓíÞÑÕäí áßí ¿ length : 24 0 - 11000011 : � : � : 4294967235 : -61 1 - 10010011 : � : � : 4294967187 : -109 2 - 11000011 : � : � : 4294967235 : -61 3 - 10101101 : � : � : 4294967213 : -83 4 - 11000011 : � : � : 4294967235 : -61 5 - 10011110 : � : � : 4294967198 : -98 6 - 11000011 : � : � : 4294967235 : -61 7 - 10010001 : � : � : 4294967185 : -111 8 - 11000011 : � : � : 4294967235 : -61 9 - 10010101 : � : � : 4294967189 : -107 10 - 11000011 : � : � : 4294967235 : -61 11 - 10100100 : � : � : 4294967204 : -92 12 - 11000011 : � : � : 4294967235 : -61 13 - 10101101 : � : � : 4294967213 : -83 14 - 00100000 : : : 32 : 32 15 - 11000011 : � : � : 4294967235 : -61 16 - 10100001 : � : � : 4294967201 : -95 17 - 11000011 : � : � : 4294967235 : -61 18 - 10011111 : � : � : 4294967199 : -97 19 - 11000011 : � : � : 4294967235 : -61 20 - 10101101 : � : � : 4294967213 : -83 21 - 00100000 : : : 32 : 32 22 - 11000010 : � : � : 4294967234 : -62 23 - 10111111 : � : � : 4294967231 : -65
解决方案
问题根源
- 编码转码错误:你的源代码文件是UTF-8编码,编译器会把字符串中的字符自动转换成UTF-8多字节序列(每个阿拉伯字符对应2个UTF-8字节),导致最终
string的字节数是24,而非Windows-1256的13字节。 - 符号扩展问题:C++中
char默认是有符号类型,当字节值大于127时,强制转换为int会触发符号扩展得到负数;转换为unsigned int时,也会先变成负数再转成超大无符号值。直接输出unsigned char会被cout当作字符处理,因不符合终端编码而显示乱码。
正确实现步骤
- 存储原始Windows-1256字节:直接用十六进制字节值初始化
string,避免编译器自动转码。 - 处理字节符号:遍历前将
char转为unsigned char,避免符号扩展。 - 打印数值而非字符:输出时将字节转为整数类型,让
cout输出数值而非字符。
修正后的代码
#include <iostream> #include <bitset> #include <string> int main() { // 替换为你字符串对应的Windows-1256十六进制字节值(需根据附图调整) const unsigned char win1256_bytes[] = {0xD3, 0xE9, 0xDE, 0xD1, 0xD5, 0xE4, 0xE9, 0x20, 0xE1, 0xDF, 0xE9, 0x20, 0xBF}; std::string myString(reinterpret_cast<const char*>(win1256_bytes), sizeof(win1256_bytes)); std::cout << "字符串字节长度: " << myString.size() << std::endl; // 输出13 for (std::size_t i = 0; i < myString.size(); ++i) { unsigned char byte = static_cast<unsigned char>(myString[i]); std::cout << i << " - " << std::bitset<8>(byte) << " : 十进制=" << static_cast<uint32_t>(byte) << " : 十六进制=" << std::hex << static_cast<uint32_t>(byte) << std::dec << std::endl; } return 0; }
代码说明
- 原始字节初始化:用
unsigned char数组存储Windows-1256原始字节,再转为string,确保每个元素都是单字节的Windows-1256编码值。 - 符号处理:将
myString[i]转为unsigned char,保证所有字节值被当作0-255的无符号数处理,避免符号扩展。 - 数值打印:用
static_cast<uint32_t>(byte)将字节转为无符号整数,让cout输出数值而非字符,同时支持十进制/十六进制切换显示。
内容的提问来源于stack exchange,提问作者Ahmad
相关产品推荐
相关产品推荐

