文章目录
- 一、介绍
- 二、算法思想
- 三、代码
一、介绍
CRC算法详解
二、算法思想
在输入的时候是直接输入的生成多项式,而我们在计算
CRC
校验码的时候需要将生成多项式转换成对应的二进制串。
转换的方式如下图(x4表示的是x的4次方
,生成多项式的1
相当于X0
)
理解了转换的方法之后,就可以设计对应的算法了。
我的思路如下:
- 先将传入的数据进行大写转换,以便之后的处理
- 再以
+
号为标志将多项式分割成多个字符串,对于上图的样例来说就是分割成x4、x3和1
- 将这些分割后的字符串存入一个列表
lis
- 由于生成多项式的最右侧必定为
1
,所以定义一个变量string
直接初始化为列表的最后一个元素- 将列表的最后一个元素删除,并对列表进行逆序(
相当于从右往左遍历生成多项式,且不遍历数字1
)- 遍历列表
lis
- 如果
string
的长度和X4、X3
中的数字值相同时,就表示该位的二进制为1- 如果
string
遍历到X3
却只有1
位的长度时,就说明当前遍历到了X0
的位置,但X2
是不存在生成多项式中的,所以需要使用一个循环补全X2
位置的0
,由于之后需要在当前位置补1
,则需要补0
的个数为len(lis[i][1])-len(string)-1
def TurnBin(expression):
'''将生成多项式转换为二进制字符串输出'''
#输入数据处理
expression = expression.upper() #大写转换
lis = list(expression.split("+")) #以加号为标志进行分割
string = lis[-1] #多项式末尾的数字1
del lis[-1]
lis = lis[::-1] #倒序
## print(lis)
#二进制转换
for i in range(len(lis)):
if len(string)==int(lis[i][1]): #满足位数与变量的数字相同时
string += "1"
else:
for j in range(int(lis[i][1])-len(string)): #用0补全相差的位数
string += "0"
string += "1"
return string[::-1]
- 进行异或操作时,由于传入两个二进制串的前置
0
已经被消除过了。(主函数中需要使用到结果的尾数进行判断
)- 所以在进行异或时,可能会存在二进制串长度不同的情况
- 则需要对输入的数据进行处理,添加较小二进制串的首部
0
使得两个二进制串位数相同。- 这样在异或运算时,只需要用一个循环同时遍历这两个字符串
- 如果对应的二进制不同时,就为结果字符串
result
的末尾添1
,否则添0
- 最后输出的时候先遍历结果
result
,如果遇到第一个有效数据时,就将当前位置及其之后的字符串以切片的方式进行返回。(消除前置0
)
def XOR(string1,string2):
'''将两个二进制串进行异或操作,不同为1'''
result = ""
#输入数据处理
if len(string1)<len(string2): #若前者的位数不足时
for i in range(len(string2)-len(string1)): #对string1的首位补0
string1 = "0" + string1
if len(string1)>len(string2): #若后者的位数不足时
for i in range(len(string1)-len(string2)): #对string2的首位补0
string2 = "0" + string2
## print(string1,string2)
#异或计算
for i in range(len(string1)):
if string1[i]!=string2[i]:
result += "1"
else:
result += "0"
## print(result)
#输出数据处理
for i in range(len(result)): #消除异或结果中的无效0
if result[i]=="1": #找到第一个有效数据时
return result[i::]
return result
- 在
CRC
函数中,先使用一个新的变量bin_expression
保存生成多项式转换后的二进制串- 在计算时需要先在数据
string
末尾添加指定个数的0
,0
的个数等于多项式中的最高次方。- 由于在将多项式转换为二进制时将会多出来一位,所以添加
0
的个数就是len(bin_expression)-1
- 然后遍历二进制数据
- 先将数据
string
的每一个字符添加到异或结果字符串crc
中,然后判断crc
与除数bin_expression
的位数- 如果位数相同时,就将两者传入
XOR
函数中进行异或操作,并返回结果给crc
- 由于在校验码生成的过程中会删除前置
0
,所以需要补0
的操作(正常来说是不需要删除多余的0,保险起见还是加了上去
)
def CRC(string,expression):
'''产生CRC校验码'''
crc = "" #最终的crc校验码
#输入数据处理
bin_expression = TurnBin(expression) #转换为二进制串
for i in range(len(bin_expression)-1): #在二进制串末尾补0
string += "0"
## print(string,bin_expression)
#CRC计算
for i in range(len(string)): #遍历被除数二进制串
crc += string[i]
if len(crc)==len(bin_expression): #当位数足够异或计算时
crc = XOR(crc,bin_expression)
## print(crc)
#输出数据处理
if len(crc)<len(bin_expression)-1: #当crc位数不足时
for i in range(len(bin_expression)-len(crc)): #在首部补0
crc = "0" + crc
if len(crc)>len(bin_expression)-1: #当crc位数过多时
crc = crc[len(crc)-len(bin_expression)+1::] #切片,消除首部多余的0
return crc
- 在检验
CRC
的步骤使用的是之前的CRC
函数- 传入的生成多项式同样需要经过二进制转换,传入二进制串数据的末尾是对应的校验码。
- 计算
CRC
校验码时,切片的范围为[0,len(string)-len(bin_expression)+1 ]
- 计算出来校验码后,就将计算出来的
crc
与原始数据的right_crc
进行比对- 如果两个校验码相同,则表示数据传输正常。
- 如果两个校验码不同,则表示数据传输出错。
def CheckCRC(string,expression): #检测传输数据是否正确,并打印结果
#输入数据处理
bin_expression = TurnBin(expression) #转换为二进制串
right_crc = string[len(string)-len(bin_expression)+1::] #原数据末尾的crc校验码
#CRC计算
crc = CRC(string[:len(string)-len(bin_expression)+1:],expression)
#检验
if right_crc==crc: #当尾部的CRC校验码,与首部数据生成的CRC校验码一致时
print("数据传输过程正常..")
else:
print("数据传输过程出错..")
print("检测出的校验码:",crc)
print("数据尾部校验码:",right_crc)
剩下的代码属于主函数中界面的设计部分,就不详细介绍了
三、代码
再变更二进制数据的某些位,并在数据末尾添加原本数据产生的
CRC
校验码进行检测
将原始数据添加上对应的
CRC
校验码进行检测
# 作者:小狐狸
# 题目:CRC循环冗余校验
def TurnBin(expression):
'''将生成多项式转换为二进制字符串输出'''
#输入数据处理
expression = expression.upper() #大写转换
lis = list(expression.split("+")) #以加号为标志进行分割
string = lis[-1] #多项式末尾的数字1
del lis[-1]
lis = lis[::-1] #倒序
## print(lis)
#二进制转换
for i in range(len(lis)):
if len(string)==int(lis[i][1]): #满足位数与变量的数字相同时
string += "1"
else:
for j in range(int(lis[i][1])-len(string)): #用0补全相差的位数
string += "0"
string += "1"
return string[::-1]
def XOR(string1,string2):
'''将两个二进制串进行异或操作,不同为1'''
result = ""
#输入数据处理
if len(string1)<len(string2): #若前者的位数不足时
for i in range(len(string2)-len(string1)): #对string1的首位补0
string1 = "0" + string1
if len(string1)>len(string2): #若后者的位数不足时
for i in range(len(string1)-len(string2)): #对string2的首位补0
string2 = "0" + string2
## print(string1,string2)
#异或计算
for i in range(len(string1)):
if string1[i]!=string2[i]:
result += "1"
else:
result += "0"
## print(result)
#输出数据处理
for i in range(len(result)): #消除异或结果中的无效0
if result[i]=="1": #找到第一个有效数据时
return result[i::]
return result
def CRC(string,expression):
'''产生CRC校验码'''
crc = "" #最终的crc校验码
#输入数据处理
bin_expression = TurnBin(expression) #转换为二进制串
for i in range(len(bin_expression)-1): #在二进制串末尾补0
string += "0"
## print(string,bin_expression)
#CRC计算
for i in range(len(string)): #遍历被除数二进制串
crc += string[i]
if len(crc)==len(bin_expression): #当位数足够异或计算时
crc = XOR(crc,bin_expression)
## print(crc)
#输出数据处理
if len(crc)<len(bin_expression)-1: #当crc位数不足时
for i in range(len(bin_expression)-len(crc)): #在首部补0
crc = "0" + crc
if len(crc)>len(bin_expression)-1: #当crc位数过多时
crc = crc[len(crc)-len(bin_expression)+1::] #切片,消除首部多余的0
return crc
def CheckCRC(string,expression): #检测传输数据是否正确,并打印结果
#输入数据处理
bin_expression = TurnBin(expression) #转换为二进制串
right_crc = string[len(string)-len(bin_expression)+1::] #原数据末尾的crc校验码
#CRC计算
crc = CRC(string[:len(string)-len(bin_expression)+1:],expression)
#检验
if right_crc==crc: #当尾部的CRC校验码,与首部数据生成的CRC校验码一致时
print("数据传输过程正常..")
else:
print("数据传输过程出错..")
print("检测出的校验码:",crc)
print("数据尾部校验码:",right_crc)
if __name__=='__main__':
while True:
print("------------------------")
print("| 0. 退出 |")
print("| 1. 产生CRC校验码 |")
print("| 2. 检测传输数据 |")
print("------------------------")
flag = int(input())
if flag==0:
break
elif flag==1:
expression = input("生成多项式: ")
string = input("二进制串:")
print(string,"的CRC校验码为: ",CRC(string,expression))
elif flag==2:
expression = input("生成多项式: ")
string = input("二进制串:")
CheckCRC(string,expression)
print("程序已终止...")