Python 练习讲解 · 18 / 25

字符编码与格雷码

用字符码表示文本;用相邻码只改变一位的格雷码表示整数。

要学习的知识点

题目

练习 18:输出字符的 ASCII 码,并进行整数与格雷码的相互转换。

输入:第一行一个 ASCII 字符,第二行一个非负整数。

参考程序:ex18.py;空白练习:lx18.py。

完整代码

以下内容与 ex18.py 一致,可对照右侧讲解阅读。

"""练习 18:输出字符的 ASCII 码,并进行整数与格雷码的相互转换。
输入:第一行一个 ASCII 字符,第二行一个非负整数。

学习说明:
- ord(character) 返回字符的编码数值;ASCII 字符只占用 ASCII 字符集范围。
- 格雷码的转换公式是 n ^ (n >> 1),^ 表示按位异或,>> 表示向右移位。
- 解码时,binary_value 保存当前还原结果;把格雷码不断右移,并与结果异或。
- 最终的 binary_value 应与输入整数相同,可用来检查转换过程。
"""
character = input()
number = int(input())
if len(character) != 1 or not character.isascii():
    raise ValueError("第一行必须输入一个 ASCII 字符")
if number < 0:
    raise ValueError("第二行必须输入非负整数")

ascii_code = ord(character)
gray_code = number ^ (number >> 1)

# 格雷码解码:格雷码与它逐次右移后的值进行异或,得到原二进制数。
binary_value = gray_code
shifted = gray_code >> 1
while shifted:
    binary_value ^= shifted
    shifted >>= 1

print("ASCII:", ascii_code)
print("gray:", gray_code)
print("decoded:", binary_value)

进阶写法

这版与初学版解决同一道题,使用更精炼的语法或标准库工具。

进阶源码:ex18_adv.py

"""练习 18 进阶版:用 ord 转码,并用逐次右移的前缀异或解码格雷码。"""
character = input()
number = int(input())
if len(character) != 1 or not character.isascii():
    raise ValueError("第一行必须输入一个 ASCII 字符")
if number < 0:
    raise ValueError("第二行必须输入非负整数")

gray_code = number ^ (number >> 1)
binary_value = 0
remaining_bits = gray_code
while remaining_bits:
    binary_value ^= remaining_bits
    remaining_bits >>= 1

print("ASCII:", ord(character))
print("gray:", gray_code)
print("decoded:", binary_value)

解码时将格雷码不断右移,并将每个前缀与结果异或;循环直到移位值为 0。

运行结果

示例输入:

A
13

程序输出:

ASCII: 65
gray: 11
decoded: 13

逐个认识函数

下表根据程序中实际调用的函数和方法整理;自定义函数的实现与算法细节见后续说明。

函数形式功能与返回值注意事项
ValueError(message)内置异常类型,用来表示参数值不符合要求。raise ValueError(...) 会立即抛错并停止当前程序流程。
str.isascii()判断字符串是否全部由 ASCII 字符组成,返回 bool。空字符串也会返回 True。
input(prompt='')读取一行文本,返回 str;若提供 prompt 会先显示提示。返回值默认是字符串,计算前通常要做类型转换。
int(value, base=10)把整数文本或数值转换为整数。int('3.5') 不合法;按指定进制解析时可传 base。
len(container)返回字符串、列表、元组等对象的元素个数。整数等没有长度的对象不能传入。
ord(character)返回单个字符对应的 Unicode 编码整数。只有限制在 ASCII 范围时才等同 ASCII 码。
print(*objects, sep=' ', end='\n')把对象转换为文本显示;返回 None。默认空格分隔并在末尾换行。

ASCII 与字符函数

函数 / 方法参数和返回值用法与注意
input()无必需参数,返回输入的一行字符串。第一行字符,第二行整数。
len(text)返回字符串字符数。检查字符长度是否为 1。Python 的字符串长度按 Unicode 码点计数。
text.isascii()无参数;字符串字符全在 ASCII 范围时返回 True。限制本题为 ASCII;空字符串对该方法返回 True,但 len 检查会挡住它。
ord(character)接受一个长度为 1 的字符串,返回其 Unicode 编码整数。本题限制 ASCII,所以结果正是 ASCII 码;一般 Unicode 字符的 ord 值不一定属于 ASCII。
int(text)将整数文本转换为 int。输入非负值,程序检查 number<0。

格雷码是什么

普通二进制相邻数可能多位变化,比如 3=011、4=100,三位都变。格雷码排序相邻项只改变一位,常用于位置编码和减少转换瞬间的读数错误。

编码公式:gray = n ^ (n >> 1)。>> 1 是二进制右移一位,^ 是按位异或:相同位得 0,不同位得 1。

函数/运算说明
^按位异或运算符,不是函数。
>>右移运算符;正整数右移一位相当于整除 2。
^=异或后赋值,等价于 a = a ^ b。

解码:逐个恢复二进制位

格雷码最高位与原二进制最高位相同。之后每一位原值等于“上一位原值 XOR 当前格雷位”。程序用前缀异或来实现:先令结果等于整个格雷数,然后将格雷码右移 1、2、3...位,依次与结果异或,直到 shifted 为 0。

binary_value = gray_code
shifted = gray_code >> 1
while shifted:
    binary_value ^= shifted
    shifted >>= 1

程序最后打印 decoded。应与原输入 number 完全相同;这是验证编码与解码互逆的办法。

代码如何运行

  1. 先按左侧题目给出的格式输入数据;程序通过 input() 读取,并在需要时转换数据类型。
  2. 程序自上而下执行语句;遇到条件、循环或函数调用时,按照右侧算法说明更新变量和处理数据。
  3. 最后由 print() 输出计算结果。可将左侧示例输入与输出逐项对照。

先自己跟踪一组小数据,记录循环前后变量的值;这比只看最终答案更容易理解程序。

自己动手试一试

测试整数 0、1、2、13 和一个更大的数;每次确认解码结果等于原数。

先在 lx18.py 中独立完成,再运行参考程序比较结果。修改程序时一次只改一个条件或步骤。