在进入正式叫用API前,还记得先前有比如四组Hash码(以十六进位表示),或者要转成bytearray (二进位binary)处理,然後又要转成字串,或者需要对utf-8进行编码吗?
这里就花些时间,一次把这些细小的转换说明一下,当然我会以Python的方式来解说,若使用其他语言的朋友,观念一致,但写法或可用的程序库或模组等使用方法不同,请再自行转换。
如同永丰提供给我们的四组Hash代码,均是以「十六进位表示的字串」,可表示的范围从0~9以及A~F,这个好处是我们可以很明确以16个可见的英数字代表一个字串,先不论人类看不看的懂或理不理解这些十六进位的字串是什麽意思,但就电脑与网路等的各种传输过程或讯息交换等作业时,可避免原本因为有各种不同语系编码误用等,造成乱码的错误。
再回想一下,我们需要把这四组16进位显示的字串,进行两两XOR运算,进行XOR运算的最基础的作法就是把他们转成二进位的bytes。(但我们今天不讲XOR)
就先举一个我们拿到的A1 Hash代码字串:86D50DEF3EB7400E
,我们怎麽将它转成Bytes的型态呢?
在Python中,可支援在宣告过程中直接字串方式贴上,但在前面加上一个b
的提示字,这样一来,则可让这个字串以一种称为Byte Object方式宣告,其特性是在ASCII的范围内的文字可直接於print()输出时印出(但仍然会有编码问题,并非所有文字都可直接列印显示)。
# 字串
A1_str = "86D50DEF3EB7400E"
print(A1_str)
# Byte Object,前面加上一个'b'
A1_ba = b"86D50DEF3EB7400E"
print(A1_ba)
# Output: b'86D50DEF3EB7400E'
A1_str_to_ba = A1_str.encode("utf-8")
print(A1_str_to_ba)
# Output: b'86D50DEF3EB7400E'
print("A1_ba == A1_str_to_ba is {}".format(A1_ba == A1_str_to_ba))
# Output: A1_ba == A1_str_to_ba is True
A1_str
是以字串方式接值,而A1_ba
则是在前面加上一个b
,因此他是一个以十六进位的显示的Bytes Object,要小心注意这个差异。
但如果我们今天没办法在宣告时加上b
的前置词时,我们能就需要透过转换的语法将字串转成Bytes Object了。
因此我们在字串型别的A1_str後面加上.encode()方法,即可将此字串以指定的编码格式方式转换成Bytes型别(预设为utf-8)。可以看到一开始直接在前面放上一个b
的Bytes Object和我们将字串转成Bytes Object的结果是相同的内容。
由於我们这个Hash代码的例子,里面放的都是英数字,因此utf-8的编码会仍以每个字元1个byte (8-bit)方式编码。
刚刚我们成功将字串转成Bytes Object,那怎麽再转回字串呢?
只要将Bytes Object再使用.decode()方法,後面带入解码的格式,很多时候我们看到文件上出现乱码,就是encode和decode的编码与解码因为使用不同的编码造成的错误。
A1_ba_to_str = A1_ba.decode("utf-8")
print(A1_ba_to_str)
# Output: 86D50DEF3EB7400E
在这里需要提到utf-8编码,此编码是采用非固定长度的方式作文字解码。简单的说,若是使用与ASCII相同的字元,例如英数字等,其长度会采用1 byte。若使用一些西欧语系的编码,会采用2 bytes长度。像中文、日文等亚洲文字,会采用3 byte的长度。
ch_01_str = "永丰API"
print("ch_01_str: {}".format(ch_01_str))
# Output: h_01_str: 永丰API
### 以上以b开头的模式下直接输入中文会出错,若要这样作,需使用ASCII code或以Hex十六进位方式输入
### 例如:b'\xe6\xb0\xb8\xe8\xb1\x90API'
# ch_01_ba = b"永丰API"
ch_01_ba_encoded = ch_01_str.encode("utf-8")
print("ch_01_ba_encoded: {}".format(ch_01_ba_encoded))
# Output: ch_01_ba_encoded: b'\xe6\xb0\xb8\xe8\xb1\x90API'
ch_hex_01_str_encoded = ch_01_ba_encoded.hex()
print("ch_hex_01_str_encoded: {}".format(ch_hex_01_str_encoded)) #hex()转出来是"字串"!
# Output: ch_hex_01_str_encoded: e6b0b8e8b190415049
ch_hex_01_ba_encoded = ch_hex_01_str_encoded.encode("utf-8")
print("ch_hex_01_ba_encoded: {}".format(ch_hex_01_ba_encoded))
# Output: ch_hex_01_ba_encoded: b'e6b0b8e8b190415049'
我们若直接将带有中文的字串,进行.encode("utf-8")转成Bytes Object格式,使用print()输出时会发现有中文的地方,会以\x
开头带2位的十六进位值,如果仔细数一下,会发现它是\xe6\xb0\xb8\xe8\xb1\x90
後面再接上API
字串。
原因是因为刚刚谈到,中文字的utf-8格式会以3 bytes的方式编码,因此:
\xe6\xb0\xb8
(3 bytes)\xe8\xb1\x90
(3 bytes)如果我们使用.hex()
语法,可将这个Bytes Object转成以十六进位显示的"字串"格式。
会看到输出为e6b0b8e8b190415049
补充说明,另外有一个模组binascii.hexlify()
可将刚刚的ch_01_ba_encoded进行转换,但转出来与.hex()差异在於hexlify()转出来的型别是Bytes Object,而不是"字串"格式。(使用前记得import binascii
)
可以透过这个线上工具做一下验证,将上述的这一串贴到左侧,可以看到「永丰API」这几个字成功被转回来:
https://onlineutf8tools.com/convert-hexadecimal-to-utf8
若我们使用程序作转换,作法如下:
# 方法1: 从原utf-8编码的Bytes Object来
# ch_01_ba_encoded 是 b'\xe6\xb0\xb8\xe8\xb1\x90API'
ori_ch_str = ch_01_ba_encoded.decode("utf-8")
print("ori_ch_str: {}".format(ori_ch_str))
# Output: ori_ch_str: 永丰API
# 方法2: 从十六进位字串来
# 注:ch_hex_01_str_encoded 是 'e6b0b8e8b190415049'字串
ori_ch_str2 = bytes.fromhex(ch_hex_01_str_encoded).decode("utf-8")
print("ori_ch_str2: {}".format(ori_ch_str2))
# Output: ori_ch_str2: 永丰API
若是直接转换的来源是从utf-8编码的Bytes Object来的,也就是刚看到的b'\xe6\xb0\xb8\xe8\xb1\x90API'
,那直接使用bytes的.decode("utf-8")即可转回原中文字。
若是中间有作过.hex()
转成纯十六进位表示法时,则使用bytes.fromhex()转换後再进行utf-8编码,亦可转回原中文字。
<<: 连续 30 天 玩玩看 ProtoPie - Day 7
前言 大家在查找程序码时可能会看到 if __name__=='__main__': 这段 code...
React 事件处理 React 和 HTML 事件处理的语法略有不同: HTML 的事件语法: &...
在 Day01 的时候我们有提到过资料可能会有杂讯、噪音,因此所使用的模型架构可以分为两个阶段:除噪...
18 - Config 这篇将介绍与上篇 Configatron 相同功能类似的 Gem - Con...
好的,假设在你的农地旁, 有人或动物不时就发出类似卡车或是车子的声音, 让你的手机半夜一直发出警报,...