《关于一个汉字为什么会有两个UTF-8编码这件事》

事情的起因是每次我从PDF里复制一段话出来粘贴到word中时,总是会出现下面这种格式错乱的情况:

这显然是由于PDF中的换行符被错误复制出来的问题,我就想拿python写个简单的脚本自动监听剪贴板并替换掉换行符,代码如下:

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
import win32clipboard
import time


def clipboard_get():
"""获取剪贴板数据"""
win32clipboard.OpenClipboard()
data = win32clipboard.GetClipboardData(win32clipboard.CF_UNICODETEXT)
win32clipboard.CloseClipboard()
return data


def clipboard_set(data):
"""设置剪贴板数据"""
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardData(win32clipboard.CF_UNICODETEXT, data)
win32clipboard.CloseClipboard()


def char_replace(txt):
if '\n' in txt:
new_txt = txt.replace('\n', '').replace('\r', '')
print('-' * 100 + f'\n【处理后】 {new_txt}')
return True, new_txt
return False, txt


def main():
recent_txt = ''
while True:
txt = clipboard_get()
if txt != recent_txt:
has_replaced, new_txt = char_replace(txt)
if has_replaced:
clipboard_set(new_txt)
recent_txt = txt
time.sleep(0.4)


if __name__ == '__main__':
main()

我再将那一段话复制到记事本里,发现换行符被很顺利的去掉了。但同时我也发现了一个在word下没发现的问题:

有一些字会比其他的字要偏细,也和正常用输入法打出来的同样的字粗细不同,我将其复制到QQ里,发现也是不同的,但是从手机上看起来就很正常:

我查询了两个“网”字的base64编码,发现他们不一样,这说明它们根本就不是同一个字!

我又想起了现在的汉字多半是UTF-8编码的,我又去查询了一下,果然它们有着不同的编码:

但是,一个汉字为什么会有两个不同的UTF-8编码呢?

我找到了UTF-8编码表:Unicode/UTF-8-character table (utf8-chartable.de)

这下终于破案了,那些奇怪的字是康熙字典部首里的部首,编码是2F00 - 2FDF,而我们正常使用的汉字叫做中日韩统一表意文字,编码是4E00 - 9FFF

随后我又在GitHub上找到了康熙部首对照字典:spider_notes/kangxi.json at master · furuiyang0715/spider_notes (github.com)

这次再改下程序就OK了:

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
import win32clipboard
import time

from clipboard.replace_table import replace_table


def clipboard_get():
"""获取剪贴板数据"""
win32clipboard.OpenClipboard()
data = win32clipboard.GetClipboardData(win32clipboard.CF_UNICODETEXT)
win32clipboard.CloseClipboard()
return data


def clipboard_set(data):
"""设置剪贴板数据"""
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardData(win32clipboard.CF_UNICODETEXT, data)
win32clipboard.CloseClipboard()


def char_replace(txt):
has_replaced = False
for old_char, new_char in replace_table.items():
if old_char in txt:
txt = txt.replace(old_char, new_char)
has_replaced = True
if has_replaced:
print('-' * 100 + f'\n【处理后】 {txt}')
return has_replaced, txt


def main():
recent_txt = ''
while True:
txt = clipboard_get()
if txt != recent_txt:
has_replaced, new_txt = char_replace(txt)
if has_replaced:
clipboard_set(new_txt)
recent_txt = txt
time.sleep(0.4)


if __name__ == '__main__':
main()

复制过来终于正常了: