Day07 - [丰收款] 浅谈binary与十六进位Hex、UTF-8文字编码转换

在进入正式叫用API前,还记得先前有比如四组Hash码(以十六进位表示),或者要转成bytearray (二进位binary)处理,然後又要转成字串,或者需要对utf-8进行编码吗?

这里就花些时间,一次把这些细小的转换说明一下,当然我会以Python的方式来解说,若使用其他语言的朋友,观念一致,但写法或可用的程序库或模组等使用方法不同,请再自行转换。

以十六进位方式表示的「字串」

如同永丰提供给我们的四组Hash代码,均是以「十六进位表示的字串」,可表示的范围从0~9以及A~F,这个好处是我们可以很明确以16个可见的英数字代表一个字串,先不论人类看不看的懂或理不理解这些十六进位的字串是什麽意思,但就电脑与网路等的各种传输过程或讯息交换等作业时,可避免原本因为有各种不同语系编码误用等,造成乱码的错误。

再回想一下,我们需要把这四组16进位显示的字串,进行两两XOR运算,进行XOR运算的最基础的作法就是把他们转成二进位的bytes。(但我们今天不讲XOR)

就先举一个我们拿到的A1 Hash代码字串:86D50DEF3EB7400E,我们怎麽将它转成Bytes的型态呢?

在字串前加上'b'格式直接宣告

在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,那怎麽再转回字串呢?
只要将Bytes Object再使用.decode()方法,後面带入解码的格式,很多时候我们看到文件上出现乱码,就是encode和decode的编码与解码因为使用不同的编码造成的错误。

A1_ba_to_str = A1_ba.decode("utf-8")
print(A1_ba_to_str)
# Output: 86D50DEF3EB7400E

试试UTF-8的中文字串

在这里需要提到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)
  • 「API」这三个字都属於ASCII可显示的字元,各占1 byte (共3 bytes),由於Python会将ASCII直接输出,因此在print()下看的到这三个字元。

如果我们使用.hex()语法,可将这个Bytes Object转成以十六进位显示的"字串"格式。
会看到输出为e6b0b8e8b190415049

补充说明,另外有一个模组binascii.hexlify()可将刚刚的ch_01_ba_encoded进行转换,但转出来与.hex()差异在於hexlify()转出来的型别是Bytes Object,而不是"字串"格式。(使用前记得import binascii)

可以透过这个线上工具做一下验证,将上述的这一串贴到左侧,可以看到「永丰API」这几个字成功被转回来:
https://onlineutf8tools.com/convert-hexadecimal-to-utf8

https://ithelp.ithome.com.tw/upload/images/20210922/20130354mF8aZ8JyRw.png

若我们使用程序作转换,作法如下:

# 方法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

>>:  威胁建模作业的前奏

【Day 19】if __name__ == '__main__' :

前言 大家在查找程序码时可能会看到 if __name__=='__main__': 这段 code...

【Day07】事件处理 Handling Events

React 事件处理 React 和 HTML 事件处理的语法略有不同: HTML 的事件语法: &...

Day10 - 除噪模型

在 Day01 的时候我们有提到过资料可能会有杂讯、噪音,因此所使用的模型架构可以分为两个阶段:除噪...

冒险村18 - Config

18 - Config 这篇将介绍与上篇 Configatron 相同功能类似的 Gem - Con...

AI ninja project [day 20] object detection

好的,假设在你的农地旁, 有人或动物不时就发出类似卡车或是车子的声音, 让你的手机半夜一直发出警报,...