Fork me on GitHub

一文秒懂如何用Python实现集装箱箱号规则校验

众所周知,海运作为一项运输方式已经非常成熟;在大大小小的海运船只上,我们看到最多的就是集装箱了,但是一艘船会有很多集装箱,运输单位是如何区分这些集装箱的标准呢?我们可以看到,每一个集装箱都有一个由字母跟数字组成的编码,按照箱型的不同,运输单位的不同,这些箱号也都各不相同。集装箱箱号就跟我们每一个中国人的身份证号码一样,是独一无二的,因此,箱号也有自己的组成规则。

箱号编码的构成

集装箱箱号编码由11位编码组成,包括三个部分:

第一部分由4位英文字母组成。这一部分又可分为两部分,分别是(前3位)箱主代码(Owner Code),表明集装箱的经营人是谁,需要由集装箱所有人自定义并且向国际集装箱局登记注册;第二部分为类型代码(第4位),包括:U(常规集装箱)、J(带有可拆卸设备)、Z(带拖车喝底盘车的集装箱)。本文以常规集装箱为例进行分析。

第二部分由6位阿拉伯数字组成。这一部分称为箱体注册码(Registration Code),或顺序号(Serial Number),是一个集装箱箱体持有的唯一标识。如果不够六位,那么就用0在前面补齐,比如一家箱主的第一个箱子,可能就是000001。

第三部分是1位阿拉伯数字,为校验码(CheckDigit)。通常在箱体上加以方框用以区别于箱体注册码。它是检验箱主代号和顺序号记录是否准确的依据,由前4位字母和6位数字经过校验规则运算得出。

箱号的校验规则

根据校验规则,箱号的每个字母与数值都有一个用作运算的对应数值,见下表:
A=10 B=12 C=13 D=14 E=15 F=16 G=17 H=18 I=19 J=20 K=21 L=23 M=24 N=25 O=26 P=27 Q=28 R=29 S=30 T=31 U=32 V=34 W=35 X=36 Y=37 Z=38

公式:第N位的箱号对应值乘以2^(N-1) (N=1,2,3………10)

以箱号“ZGLU3195510”为例,前4个字分别对应的值为:38,17,23,32。

  • Z = 38 * 2 ^ 0 = 38
  • G = 17 * 2 ^ 1 = 17
  • 1 = 1 * 2 ^ 9 = 512

以此类推,一直到第十位计算完成,也就是第六个数字计算完成,然后把这些值累加,为3508。

校验规则:将累加值与11取模

3508对11取模就是10,当余数为10时需要再对10取模,也就是说我们的最后一个数字(校验码)应当是0。

注意:对11取模后余数可能为两位,如为10时,那么我们就需要再次对10取模,所以我们可以先对11取模,再对10取模。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# _*_ coding:utf-8 _*_
import math

# 建立字母数字的分值对应
def characterConversion(str):
# 转换成大写字母
str = str.upper()
basic_character = "0123456789A?BCDEFGHIJK?LMNOPQRSTU?VWXYZ"
for i in range(0, len(basic_character)):
if str == basic_character[i]:
return i

def CheckCartonNo(containerId):
sum = 0
containerId_list = list(containerId)

# 计算前10位参数的和
for i in range(0, 10):
# print(f"当前位置为{i},字母为{containerId[i]},当前参数对应的的数值为{characterConversion(containerId[i])}")
# print(f"当前计算公式为[{containerId[i]}* 2的{i}次方],当前的值为{characterConversion(containerId[i]) * (2 ** i)}")
sum += characterConversion(containerId[i]) * (2 ** i)

# 将累加的和对11进行模运算:sum % 11,当校验位等于10时要继续模运算,sum % 11 % 10,保证最终结果为0~9直接的数
print(sum)
check_digit = sum % 11 % 10
print(check_digit)

if int(check_digit) == int(containerId_list[-1]):
print(f"当前箱号{containerId}正确,校验位为{check_digit},通过校验!")
else:
print(f"当前箱号{containerId}错误,校验位为{check_digit},验证不通过!")

if __name__ == "__main__":
containerId = input("请输入箱号>>>")
if len(containerId) == 11:
list1 = []
list2 = []

for i in range(0, len(containerId)-7):
list1.append(containerId[i])

for i in range(4, len(containerId)):
list2.append(containerId[i])

letter_list = "".join(list1)
number_list = "".join(list2)

if letter_list.isalpha() == True:
if number_list.isdigit() == True:
CheckCartonNo(containerId)
else:
print(f"后面7位位必须是数字,箱号错误!")
else:
print(f"前面4位必须是字母,箱号错误!")
else:
print(f"箱号长度一共11位,箱号错误")

执行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
huixing@huihangdeMacBook-Pro ~/OpenSource/checkContainerRules python3 cntr.py
请输入箱号>>>A31U2828288
前面4位必须是字母,箱号错误!
huixing@huihangdeMacBook-Pro ~/OpenSource/checkContainerRules python3 cntr.py
请输入箱号>>>AAAA2345G54
后面7位位必须是数字,箱号错误!
huixing@huihangdeMacBook-Pro ~/OpenSource/checkContainerRules python3 cntr.py
请输入箱号>>>RTRTRT
箱号长度一共11位,箱号错误
huixing@huihangdeMacBook-Pro ~/OpenSource/checkContainerRules python3 cntr.py
请输入箱号>>>ZGXU2937057
当前箱号ZGXU2937057正确,校验位为7,通过校验!
huixing@huihangdeMacBook-Pro ~/OpenSource/checkContainerRules python3 cntr.py
请输入箱号>>>ZGXU2937058
当前箱号ZGXU2937058错误,校验位为7,验证不通过!

参考资料

涨知识!带你解读集装箱号,看似杂乱的箱号却有规律可循!
集装箱编号校验码规则(JavaScript版本)