You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何以数值形式遍历字符串字节?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
解决方案

问题根源

  1. 编码转码错误:你的源代码文件是UTF-8编码,编译器会把字符串中的字符自动转换成UTF-8多字节序列(每个阿拉伯字符对应2个UTF-8字节),导致最终string的字节数是24,而非Windows-1256的13字节。
  2. 符号扩展问题:C++中char默认是有符号类型,当字节值大于127时,强制转换为int会触发符号扩展得到负数;转换为unsigned int时,也会先变成负数再转成超大无符号值。直接输出unsigned char会被cout当作字符处理,因不符合终端编码而显示乱码。

正确实现步骤

  1. 存储原始Windows-1256字节:直接用十六进制字节值初始化string,避免编译器自动转码。
  2. 处理字节符号:遍历前将char转为unsigned char,避免符号扩展。
  3. 打印数值而非字符:输出时将字节转为整数类型,让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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 13:45:26