资讯动态

ASCII码对照表:字符编码原理、速查技巧与串口乱码排查

发布时间:2026/10/2 9:20:04 来源:尧图企业网站定制
1. 先聊清楚一张 ASCII 对照表到底值不值得收藏ASCII 码对照表这个东西第一次见到的人多半会觉得它就是一张枯燥的数字表背下来干嘛但凡是写过几年代码、调过串口、扒过二进制文件、做过协议解析的人电脑里大概率都存着一份 ASCII 码对照表甚至有人打印出来贴在显示器边上。原因很简单它是计算机世界里最底层、最通用、最不会过时的一张“字典”。ASCII 的全称是 American Standard Code for Information Interchange中文一般叫“美国信息交换标准代码”。它做的事情用一句话说清楚就是把 128 个常用字符和 0 到 127 这 128 个整数一一对应起来。你敲一下键盘上的字母 A计算机内部看到的其实是数字 65你敲一下数字 0计算机看到的是 48你按一下回车计算机看到的是 13 或者 10取决于系统。这张表就是人和机器之间的翻译手册。那它适合谁我大概分几类。刚入门编程的同学学 C 语言的时候老师一定会让你看这张表因为A和65之间的关系是理解字符类型的第一步。做嵌入式、串口通信、硬件调试的工程师就更不用说了收到的都是一串十六进制没有这张表根本看不懂对面在发什么。做数据处理、日志分析、文本清洗的处理乱码、不可见字符、换行符差异的时候也离不开它。还有一类是做安全、逆向、抓包分析的看二进制数据流时ASCII 表就是眼睛。我自己最开始接触这张表是在写一个串口收数据的程序对方发过来一串十六进制48 65 6C 6C 6F当时一脸懵查了表才知道是 “Hello”。那次之后我就把这张表背了个七七八八后来发现真正需要死记的其实只有几个关键锚点剩下的都能现场推。下面我就把这张表拆开揉碎讲一遍包括它的结构逻辑、记忆方法、实际用法还有我这些年踩过的坑。2. ASCII 码的整体结构128 个位置是怎么分配的2.1 为什么是 128 个而不是 256 个很多人第一次听说 ASCII 只有 128 个字符会有点意外因为在他们的印象里一个字节是 8 位能表示 256 种状态。这里就涉及一个经典的历史设计取舍。ASCII 最早是在 1963 年定下来的那会儿一个字符用 7 位来编码就够了。为什么是 7 位因为当时通信线路的可靠性有限第 8 位经常被拿来做奇偶校验位用来检测传输过程中有没有出错。也就是说真正的数据只占 7 位最高位留给校验。7 位能表示 2 的 7 次方也就是 128 个位置编号 0 到 127。后来计算机体系逐渐稳定校验位不再那么必要有人就把第 8 位也用起来扩展出 128 到 255 这另外 128 个位置这就是所谓的“扩展 ASCII”。但扩展 ASCII 从来没有一个统一标准不同厂商、不同地区各搞一套导致同一个字节在不同编码下显示成完全不同的字符这也是早年乱码问题的万恶之源。所以严格意义上讲标准 ASCII 就只有 0 到 127 这 128 个。我个人的建议是只要你的场景不涉及欧洲特殊字符或者特殊符号一律按标准 ASCII 来理解遇到 128 以上的字节先警惕八成是编码不一致导致的。2.2 这 128 个位置的分区逻辑这张表不是随便排的它的排列有着相当清晰的规律理解了分区逻辑记忆量能减少一大半。整体上可以分成四大块区间十进制范围十六进制范围内容类型说明控制字符区0 - 310x00 - 0x1F不可打印用于控制设备、格式控制空白与符号区32 - 470x20 - 0x2F可打印空格和常见标点数字区48 - 570x30 - 0x39可打印字符 0 到 9符号区58 - 640x3A - 0x40可打印冒号到 at 符号大写字母区65 - 900x41 - 0x5A可打印A 到 Z符号区91 - 960x5B - 0x60可打印方括号到反引号小写字母区97 - 1220x61 - 0x7A可打印a 到 z符号区123 - 1260x7B - 0x7E可打印花括号到波浪号删除符1270x7F不可打印DEL这个分区告诉你一个重要事实数字、大写字母、小写字母在表里都是连续排列的。连续意味着什么意味着你只要记住每一段的起点剩下的靠加法就能推出来。比如记住A是 65那E就是 65 加 4 等于 69。记住a是 97那z就是 97 加 25 等于 122。这就是不用死记硬背的核心思路。2.3 可打印字符和不可打印字符的边界32 到 126 这 95 个字符是可以正常显示出来的叫可打印字符。0 到 31 加上 127 是控制字符你在屏幕上一般看不到它们但它们在实际数据里无处不在。空格是 32它是可打印字符里最特殊的一个因为它显示出来是“什么都没有”但确实占一个字符位置。这里有个新手经常搞混的点空格和空字符不是一回事。空格是 32是一个实实在在的字符占位置空字符NUL是 0表示“什么都没有”在 C 语言里用来标记字符串结束。这两者在调试时造成的 bug 完全不同空格多了会导致匹配失败NUL 出现在中间会导致字符串被截断。我在处理用户输入的文本时被这两个东西坑过不止一次。3. 完整 ASCII 对照表与关键锚点速查3.1 控制字符区完整对照表这部分在协议解析、串口调试、日志过滤时用得极多建议至少把常用的几个混个脸熟。十进制十六进制缩写含义常见用途00x00NUL空字符字符串结束标记10x01SOH标题开始报文头20x02STX正文开始报文起始30x03ETX正文结束报文结束40x04EOT传输结束会话结束50x05ENQ询问轮询60x06ACK确认应答正确70x07BEL响铃终端蜂鸣80x08BS退格删除前一字符90x09HT水平制表符也就是 Tab100x0ALF换行Unix 换行符110x0BVT垂直制表符少见120x0CFF换页打印分页130x0DCR回车Windows 换行组成部分140x0ESO移出切换字符集150x0FSI移入切换字符集160x10DLE数据链路转义透明传输170x11DC1设备控制1流控 XON180x12DC2设备控制2少见190x13DC3设备控制3流控 XOFF200x14DC4设备控制4少见210x15NAK否认应答错误220x16SYN同步同步传输230x17ETB传输块结束分块传输240x18CAN取消中断传输250x19EM介质结束少见260x1ASUB替换常被用作文件结束标记270x1BESC转义终端控制序列前缀280x1CFS文件分隔符少见290x1DGS分组分隔符少见300x1ERS记录分隔符少见310x1FUS单元分隔符少见1270x7FDEL删除早期纸带打孔删除我标一下几个真正需要重点关注的0x00NUL、0x09Tab、0x0ALF、0x0DCR、0x1BESC、0x7FDEL。这几个在日常开发里出现频率极高剩下的遇到再查就行。3.2 可打印字符区完整对照表下面这张是打印出来贴墙上的那种表我按十进制顺序列出 32 到 126 全部内容。十进制十六进制字符十进制十六进制字符320x20空格800x50P330x21!810x51Q340x22820x52R350x23#830x53S360x24$840x54T370x25%850x55U380x26860x56V390x27870x57W400x28(880x58X410x29)890x59Y420x2A*900x5AZ430x2B910x5B[440x2C,920x5C\450x2D-930x5D]460x2E.940x5E^470x2F/950x5F_480x300960x60490x311970x61a500x322980x62b510x333990x63c520x3441000x64d530x3551010x65e540x3661020x66f550x3771030x67g560x3881040x68h570x3991050x69i580x3A:1060x6Aj590x3B;1070x6Bk600x3C1080x6Cl610x3D1090x6Dm620x3E1100x6En630x3F?1110x6Fo640x401120x70p650x41A1130x71q660x42B1140x72r670x43C1150x73s680x44D1160x74t690x45E1170x75u700x46F1180x76v710x47G1190x77w720x48H1200x78x730x49I1210x79y740x4AJ1220x7Az750x4BK1230x7B{760x4CL1240x7C|770x4DM1250x7D}780x4EN1260x7E~790x4FO这张表信息密度很高但真正需要记住的锚点其实就这么几个0x20 是空格0x30 是字符 00x41 是 A0x61 是 a0x7A 是小写 z0x7F 是 DEL。记住这几个其他的都能通过偏移量算出来。3.3 十六进制视角下的规律我强烈建议养成用十六进制看 ASCII 的习惯因为规律在十六进制下特别明显。你看数字 0 到 9 落在0x30到0x39低四位刚好就是它代表的数值本身。字符7的编码是0x37低四位 7完美对应。大写字母 A 到 O 落在0x41到0x4FP 到 Z 落在0x50到0x5A。小写字母 a 到 o 落在0x61到0x6Fp 到 z 落在0x70到0x7A。大写字母和小写字母之间差了0x20也就是十进制的 32。这个0x20的差值是个宝藏规律后面讲大小写转换的时候会重点用到。4. 不用死记硬背几个实用的推算技巧4.1 从字符反推编码的通用方法先说最笨但最稳的方法就是“找锚点加偏移”。比如有人问你r的 ASCII 码是多少你不用背直接在脑子里过一遍a是 97r是 a 后面第 17 个字母a 排第 0 个b 是 1依此类推r 是 1797 加 17 等于 114。验算一下十六进制97 是0x61114 是0x72。这个方法的特点是只要记住a和A两个起点26 个字母全都能推出来。数字也一样0是 48那么9就是 48 加 9 等于 57。想求字符5对应的数值直接用 53 减 48 等于 5。这个“减起点”的操作在代码里天天用后面会讲。4.2 大小写转换只需要一次位运算这是我个人觉得 ASCII 设计里最优雅的地方。看这两组数A是 65二进制0100 0001a是 97二进制0110 0001对比一下只有第 5 位从 0 开始数不一样大写是 0小写是 1。而这一位对应的权重正好是 32也就是0x20。所以大写转小写把这一位置 1也就是c | 0x20或者直接c 32。小写转大写把这一位置 0也就是c ~0x20或者直接c - 32。这个技巧在写底层代码时非常好用因为位运算比调用字符串函数快得多。我做过一个压力测试在需要处理几千万次大小写转换的场景下位运算版本比标准库函数快了接近一个数量级。当然日常业务代码里直接用语言自带的函数就行清晰第一只有在性能敏感或者极底层的地方才值得手写位运算。4.3 判断字符类型的区间技巧写校验、写解析器的时候经常要判断“这个字符是不是数字”“是不是字母”。用 ASCII 区间判断是最直接的方式。下面这段伪代码展示了典型写法// 判断是否为数字字符 int is_digit(char c) { return c 0 c 9; } // 判断是否为大写字母 int is_upper(char c) { return c A c Z; } // 判断是否为小写字母 int is_lower(char c) { return c a c z; } // 判断是否为十六进制字符 int is_hex(char c) { return (c 0 c 9) || (c A c F) || (c a c f); }这里有个容易写错的点不能写成a c z因为 C 语言里这会先算a c得到一个 0 或 1再拿这个结果去和z比较结果永远为真。这个坑我见过太多人踩编译器还不一定报错排查起来很痛苦。5. 实操环节把 ASCII 表真正用起来5.1 案例一手写一个十六进制转字符串的解码器假设你在调试串口收到一串十六进制数据48 65 6C 6C 6F 2C 20 41 53 43 49 49 21想把它还原成可读文本。我们手动对照一下表十六进制十进制字符0x4872H0x65101e0x6C108l0x6C108l0x6F111o0x2C44,0x2032空格0x4165A0x5383S0x4367C0x4973I0x4973I0x2133!拼起来就是Hello, ASCII!。这个过程在代码里就是一次简单的类型转换但在调试现场手动对照表能让你在没有工具的情况下快速判断数据对不对。5.2 案例二处理换行符差异引发的诡异 bug这个案例我印象特别深。早年我写一个日志分析脚本读进来的文本按行分割总是不对末尾老是带一个看不见的字符。后来把字符编码打出来才发现文件是在 Windows 上生成的每行结尾是\r\n也就是0x0D 0x0A而我的脚本按\n0x0A切分结果每行末尾都残留一个0x0D。不同系统的换行约定大概是这样系统换行表示十六进制Unix / Linux / macOS 现代版本LF0x0AWindowsCRLF0x0D 0x0A经典 Mac OS已淘汰CR0x0D解决办法有两种一种是读取时用文本模式让运行时自动转换另一种是手动把\r\n统一替换成\n。我后来形成了习惯凡是处理外部来源的文本第一步永远是先做换行符归一化再干别的。这个预处理动作看起来多余但省下来的排查时间非常值。5.3 案例三一个统计字符类型的小工具下面这段 Python 代码演示了如何用 ASCII 区间来统计一段文本里各类字符的数量逻辑很直白但把 ASCII 的知识点全串起来了def classify_text(text): stats { digits: 0, upper: 0, lower: 0, spaces: 0, printable_other: 0, control: 0, } for ch in text: code ord(ch) # 取出字符对应的 ASCII 码 if 48 code 57: stats[digits] 1 elif 65 code 90: stats[upper] 1 elif 97 code 122: stats[lower] 1 elif code 32: stats[spaces] 1 elif code 32 or code 127: stats[control] 1 else: stats[printable_other] 1 return stats sample Hello ASCII 2024!\n\tTab and CR\r\n print(classify_text(sample))跑出来的结果能让你清楚看到文本里有多少不可见字符。我经常用类似的逻辑来给用户提交的内容做体检尤其是从外部系统导进来的数据先跑一遍统计能提前发现大量隐藏问题。6. 常见坑与排查技巧实录6.1 高频问题速查表现象可能原因排查方法解决思路字符串比较总是不相等末尾有不可见字符打印每个字符的编码先 trim 再比较数字转换结果不对混淆了字符编码和数值检查是否忘了减0用c - 0取值按行读取多出空行Windows 换行符残留查看行尾字节统一换行符中文旁边出现乱码编码不一致确认输入输出编码全程统一编码二进制数据被截断中间出现 NUL用十六进制查看用二进制模式读取大小写转换结果异常只处理了字母先判断区间再转换加字符类型判断6.2 三个我会反复提醒别人的细节第一个永远不要假设输入是干净的。我见过太多程序在处理用户输入时直接崩溃原因就是输入里混了控制字符、全角符号、零宽字符。拿到数据先做一遍清洗和校验这个习惯能帮你挡掉大量诡异问题。第二个调试时优先看十六进制。人眼很容易被“看起来一样”的字符骗过去比如普通的空格0x20和不间断空格0xA0页面上一模一样编码完全不同。把数据打到十六进制再对比一眼就能看出差别。我常用的命令是xxd或者hexdump处理小文件特别方便。第三个别把扩展 ASCII 当标准 ASCII 用。128 以上的字节在不同编码里含义完全不同如果你的程序里出现了0x80到0xFF的字节就得先搞清楚它到底是什么编码不然一定会出问题。我早年就被一个0xA3坑过同一个字节在一种编码下是英镑符号在另一种编码下是别的字符折腾了大半天。6.3 关于记忆的个人心得最后说点轻松的。ASCII 表看起来有 128 项但真正需要背下来的不到十个。我的做法是只记锚点其余全部现场推。具体锚点就是A是 65a是 97两者差 320是 48数字字符减 48 得数值空格是 32DEL 是 127。有了这几个点配合十六进制下的明显规律任何字符的编码你都能在几秒钟内算出来。我在实际使用中发现用得越频繁记得就越牢。与其一开始硬背整张表不如遇到一次查一次查得多了自然就记住了。真正重要的不是把表背下来而是理解它的排列逻辑知道什么时候该去查表、查哪一部分。这个思路我觉得比死记硬背管用得多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑