問題引出
我們在程序打印輸出時,如何我們所輸出的字符中包含emoji文本,或者其它特殊的字符文本,則我們的打印對齊效果將出現錯位。以下代碼復現了這一效果(tips: 馬老師 前面的 | 符號是為了觀察對齊效果):
# -*- coding:UTF-8 -*-
# region 引入必要依賴
from DebugInfo.DebugInfo import *
# endregion
if __name__ == "__main__":
畫板 = 打印模板()
畫板.打印空行(2)
畫板.準備表格()
畫板.添加一行('序號', '姓名', '自評', '班主任').修飾行(青字) # 作為標題行
畫板.添加一行('1', '小紅', '我很開朗', '|馬老師')
畫板.添加分隔行()
畫板.添加一行('2', '豬小明', '我得了很多小花 ❌', '|馬老師')
畫板.添加分隔行()
畫板.添加一行('3', '趙虹', '我有愛心♥', '|馬老師')
畫板.添加分隔行()
畫板.添加一行('4', '張天志', '我是女生♀️我有長頭髮', '|馬老師')
畫板.添加空行()
畫板.展示表格()
👆以上代碼的運行打印對齊如下:
我們可以觀察到,豬小明行,馬老師靠前了
我們又可以觀察到,張天志行,馬老師靠後了
原因解釋
為什麼會出現上面的對齊的現象呢?這就要從字體説起了。
我們電腦上,所顯示的符號肯定是通過某一個字體來顯示的。所以同一個字,我們在宋體下看到的效果,和在黑體下看到的效果,是不一樣的。
一個字符,顯示其效果所佔用的屏幕像素數量,稱為字符的顯示像素寬度;為方便其見,我們將字符的像素寬度相對於英文字符空格所佔用的像素寬度的比值,做為下文我們要描述的字符顯示寬度值。
- 顯然,英文空格的字符顯示寬度值是 1
- 一個英文字符(大寫和小寫)的顯示寬度值是 1
- 對於以下顯示的楷體字體下的中文,一個字符的顯示寬度值是 2
顯示,對於任何可以在電腦上顯示的字符,其都有一個顯示寬度,只是不同的字符,在不同的字體下,其顯示寬度值不同罷了。
有了以上規律後,我們如果需要對齊文本,就會比較容易了。我們計算字符的顯示寬度,根據其顯示寬度,計算並補充對應數量的空格後,文本就可以達到對齊的效果。
那現在來説上面馬老師對不齊的問題。根據上文中的對齊原理的解釋,馬老師對不齊,肯定是文本中存在了這樣的字符,這字符計算的顯示寬度,與其實際顯示所佔用的寬度不一致,導致在補充空格時空格數量計算錯誤。
找出真兇
在上面的表格中,我們發現符號 ❌ ♥ ♀️ 是不常的字符。我們把這幾個字符拿掉,再來觀察對齊效果,如下👇:
# -*- coding:UTF-8 -*-
# region 引入必要依賴
from DebugInfo.DebugInfo import *
# endregion
if __name__ == "__main__":
畫板 = 打印模板()
畫板.打印空行(2)
畫板.準備表格()
畫板.添加一行('序號', '姓名', '自評', '班主任').修飾行(青字) # 作為標題行
畫板.添加一行('1', '小紅', '我很開朗', '|馬老師')
畫板.添加分隔行()
# 畫板.添加一行('2', '豬小明', '我得了很多小花 ❌', '|馬老師')
畫板.添加一行('2', '豬小明', '我得了很多小花 ', '|馬老師')
畫板.添加分隔行()
# 畫板.添加一行('3', '趙虹', '我有愛心♥', '|馬老師')
畫板.添加一行('3', '趙虹', '我有愛心', '|馬老師')
畫板.添加分隔行()
# 畫板.添加一行('4', '張天志', '我是女生♀️我有長頭髮', '|馬老師')
畫板.添加一行('4', '張天志', '我是女生我有長頭髮', '|馬老師')
畫板.添加空行()
畫板.展示表格()
👆以上代碼運行效果如下👇:
嗯,對齊效果非常漂亮。
所以,我們將問題的焦點放在符號 ❌ ❤ ♀️ 這三個字符上。 以下代碼打印並顯示了這三個字符的顯示寬度和實際佔用寬度。
# -*- coding:UTF-8 -*-
# region 引入必要依賴
from DebugInfo.DebugInfo import *
# endregion
if __name__ == "__main__":
畫板 = 打印模板()
畫板.打印空行(2)
畫板.準備表格()
畫板.添加一行('字符','顯示寬度值').修飾行(青字)
畫板.添加分隔行()
畫板.添加一行('❌|',顯示寬度('❌'))
畫板.添加一行('♥|',顯示寬度('♥'))
畫板.添加一行('♀️|',顯示寬度('♀️'))
畫板.添加空行()
畫板.展示表格()
👆以上代碼運行效果如下👇:
上圖我們可以看到(注意看參考符號 | 的位置):
- 字符 ❌ 顯示佔用寬度為1, 計算的顯示寬度是2 (這將導致在對齊補空格時,少補一個空格)
- 字符 ♥ 顯示佔用寬度為1,計算的顯示寬度也是1 (實際顯示寬度和計算顯示寬度一致,對齊補齊空格正常)
- 字符 ♀️ 顯示佔用寬度為2,但計算的顯示寬度為1 (這將導致在對齊補空格時,多補一個空格)
所以,對齊出錯的根本原因在於符號 ♥ 和 ♀️ 在終端顯示時,顯示這兩個字符所佔用的字符寬度與計算的字符寬度不一致,導致在計算對齊補空格時,補了錯誤數量的空格。
補救措施
有了以上的分析,我們知道了出現對齊錯位的根本原因在於部分特殊的字符顯示寬度值的計算與實際不符導致,那麼我們對應的解決方案也就明朗了:修正特殊字符的顯示寬度值
如下的代碼,我們指定了特殊字符的顯示寬度值,並將其告訴了【打印模板對象】(這裏是畫板),然後我們又打印顯示了帶有特殊字符的文本,觀察其對齊效果:
# -*- coding:UTF-8 -*-
# region 引入必要依賴
from DebugInfo.DebugInfo import *
# endregion
if __name__ == "__main__":
畫板 = 打印模板()
畫板.打印空行(2)
畫板.準備表格()
畫板.設置特殊字符寬度字典({'❌': 1, '♀': 2}) # 修正特殊符號的顯示寬度值
畫板.添加一行('序號', '姓名', '自評', '班主任').修飾行(青字) # 作為標題行
畫板.添加一行('1', '小紅', '我很開朗', '|馬老師')
畫板.添加一行('2', '豬小明', '我得了很多小花❌', '|馬老師')
畫板.添加一行('3', '趙虹', '我有愛心♥', '|馬老師')
畫板.添加一行('4', '張天志', '我是女生♀️我有長頭髮', '|馬老師')
畫板.添加空行()
畫板.展示表格()
👆上面的代碼中,請留意 設置特殊字符寬度字典 方法,其修正了符號 ❌和 ♀️ 的顯示寬度值,這幫助程序正確的理解和計算了字符的實際顯示寬度,從而在對齊補齊空格時,可以補齊正確數量的空格。
其它的坑
在以上的分析過程中,我們所提到,所有在電腦上顯示處理的符號,都依賴於字體,這也就是説,在不同的字體下,同一個符號可能顯示的寬度(相對於空格或者符號 -),是有可能不同的,現觀察到的部分字體中,英文字符的寬度如果計算為單位1,中文字符的寬度是1.5,在這種非整數倍的字體下,遇到中英文混合情況時,對齊處理是非常難的,甚至是無法做到的。
對於特殊字符,同樣在不同的字體下,其顯示寬度也是不同的,在實際的應用中要多加留意處理。
另外,為了方便文本對齊的計算,大家在實際使用時,需要注意終端所使用的字體是否是等寬字體,非等寬字體下,可能出現字體寬度不是整數的情況,對齊處理效果會受到影響。
小結
非常感謝大家的關注和閲讀,如果哪裏有些的不對的地方,望批評指出,以便及時修正。