C# 普通字符串与含\x转义十六进制字符的字符串转byte[]结果异常问题
C# 字符串转byte[] 双场景适配方案
转换异常的根因
当前使用Encoding.ASCII.GetBytes得到不符合预期的输出,核心是ASCII编码的映射规则限制:
- ASCII编码仅支持将Unicode码点在0~127范围内的字符映射为对应单字节值
- 示例转义字符串里的
\xCD(码点205)、\xEF(码点239)、\xD7(码点215)都超出ASCII的可映射范围,转换时会被统一替换为无法识别的字符'?',对应固定字节值63 - 剩余的
\x01(码点1,在ASCII范围内)、\x30(对应字符'0',码点48)可正常映射,最终输出的63、1、63、63、48就是这个替换逻辑导致的。
适配两类转换需求的实现方案
根据字符串的实际存储形式,选择对应的转换逻辑即可:
场景1:字符串为代码中通过\x转义直接赋值的实际字符(即示例中string word = "\xCD\x01\xEF\xD7\x30"的情况)
这类场景下字符串的每个字符的Unicode码点和目标字节值一一对应,不需要做十六进制文本解析,直接替换匹配的编码即可:
- 使用
Encoding.Latin1(ISO-8859-1)编码完成转换,该编码的映射规则是将0~255范围的Unicode码点直接映射为对应单字节值,完全匹配转换预期 - 这套编码对普通字符串(如"apple")的转换结果和ASCII编码完全一致,因为ASCII是Latin1编码的前128个字符子集,一套逻辑就能同时兼容两类字符串的转换,不需要额外做分支判断
// 含\x转义的字符串转换 string escapeWord = "\xCD\x01\xEF\xD7\x30"; byte[] escapeBytes = Encoding.Latin1.GetBytes(escapeWord); // 转换结果的字节值依次为0xCD、0x01、0xEF、0xD7、0x30,符合预期 // 普通字符串转换,结果和ASCII编码无差异 string normalWord = "apple"; byte[] normalBytes = Encoding.Latin1.GetBytes(normalWord);
场景2:字符串为字面存储的转义文本(即字符串的实际内容为\xCD\x01这类可见的\x字符,而非转义后的实际字符)
这类场景常见于从配置文件、外部文本源读入内容的情况,字符串中存储的是普通的反斜杠、x、十六进制数字字符,不是转义后的控制字符,此时不能直接走编码转换,需要先提取每段转义对应的十六进制值再解析为字节:
using System.Text.RegularExpressions; // 从外部读入的字面转义文本,用@标记避免C#本身的转义解析 string escapeText = @"\xCD\x01\xEF\xD7\x30"; // 正则匹配所有\x开头的两位十六进制值 MatchCollection matches = Regex.Matches(escapeText, @"\\x([0-9A-Fa-f]{2})"); List<byte> byteBuffer = new List<byte>(); foreach (Match match in matches) { // 将匹配到的两位十六进制字符串转换为对应字节值 byte currentByte = Convert.ToByte(match.Groups[1].Value, 16); byteBuffer.Add(currentByte); } byte[] resultBytes = byteBuffer.ToArray();
避坑提醒:不要使用
Encoding.UTF8、Encoding.Unicode这类多字节编码做上述转换,这类编码会将单字符映射为多字节序列,无法实现“一个字符对应一个目标字节值”的转换效果。
内容的提问来源于stack exchange,提问作者Tyler
相关产品推荐
相关产品推荐

