当前位置: 首页 > 办公技巧 > 正文

xlsx表格办公实用技巧(如何使用xlwt精确控制Excel表格列宽)

  • 叁碗诸角 叁碗诸角
  • 办公技巧
  • 2023-07-11 19:40:30
  • 0

一、问题场景

xlwt是一个用于生成xls文件的python代码包,通常配合pandas使用。xlwt中设置表格列宽的代码如下:

sheet.col(0).width=X #X是一个小于65536的正整数,否则系统报错。

但是这个X代表什么呢? 和我们使用Excel打开文件后看到的列宽存在什么对应或映射关系?如果需要精确控制列宽,如何设置这个值?

xlwt设置的width和Excel中显示的列宽存在什么关系?

有文章说在xlwt中,列宽的度量单位是一个字符的1/256。换言之,如果需要设置10个字符的列宽,这个值就是2560。但是如果编写并运行上图左侧的代码生成一个xls文件,首列列宽设为2560,打开这个文件查看,你会发现首列列宽是9.29,而不是10。这个说法显然是不成立的。

要回答这些问题,首先我们要了解在Excel中看到的列宽是什么。


二、Excel中的列宽表示

我们在Excel中看到的列宽,是该列能够容纳的字符数。注意:是字符数!而且这个字符不是任意的,而是Excel文件默认字体中的字符0。

举例:如果默认字体为Arial 10磅,列宽为8.43(默认列宽),那么该列能够容纳8.43个Arial 10磅的0。

我们可以把列宽设为10,然后输入10个0进行验证。

Excel使用字符数表示列宽,符合人的直觉,用起来比较方便。

在Excel VBA中, 列宽字符数通过Columns(1).ColumnWidth读写,列宽磅数(points) 通过Columns(1).Width读取,但不能写入。

Sub set_width()For i = 2 To 21 Columns(i).ColumnWidth = i - 1 '第2-21列设置列宽字符数为1-20, 第1列保持默认NextFor i = 1 To 21 Cells(1, i) = Columns(i).ColumnWidth '显示第1-21列的列宽字符数 Cells(2, i) = Columns(i).Width * 4 / 3 '列宽像素 Cells(3, i) = Columns(i).Width '列宽磅值NextEnd Sub

列宽字符数、列宽磅数和列宽像素的换算公式如下(默认字体为Arial/宋体 10磅):

公式1: 列宽字符数*7 5=列宽像素

公式2:列宽磅数=列宽像素*3/4(DPI为96的情况下)

公式3:列宽像素=列宽磅数*4/3

公式1涉及的知识比较复杂,可以到https://www.iso.org/下载ISO/IEC 29500-1:2016标准文件,阅读第1601页上关于width的解释,认真理解下面这段话:

Column width measured as the number of characters of the maximum digit width of the numbers 0, 1, 2, …, 9 as rendered in the normal style's font. There are 4 pixels of margin padding (two on each side), plus 1 pixel padding for the gridlines.


三、xlwt中的width和Excel列宽字符数的对应关系

xlwt如何存储width的值,Excel如何把该值转换为列宽字符数,本文不深入讨论。在xlwt包内Column.py文件中,开发者定义了width转换width_in_pixels的公式:

def width_in_pixels(self):# *** Approximation **** return int(round(self.width * 0.0272 0.446, 0))

根据该公式可知,xlwt的width_in_pixels只是基于width计算得到的一个近似值,二者之间并不存在线性关系。简单测试发现,近似像素和实际像素存在0-2个误差。

虽然大多数情况下0-2个像素误差并不要紧,但是如果需要把width精确控制到像素级别(比如套打),这个公式显然不够精确。我们需要更为精确的计算公式。


四、width精确计算公式

经过多次测试,终于找到了这个公式:

公式4:width=round(列宽字符数*256 182.8571,0)

解释:在xlwt中,一个字符的宽度为256,相当于7像素,那么字符两侧的5像素=256*5/7=182.8571。由于width只能是整数,所以使用round函数取整(虽然python的round函数存在误差,但在这个公式里没有出现)。

这个公式帮助我们理解xlwt列宽和Excel列宽字符数之间的对应关系,也就有了新的列宽设置思路:只考虑列宽字符数(再次强调:这符合人的直觉),然后用公式去计算这个width到底是多少。

基于上面4个公式,很容易写出基于像素和磅值的列宽计算公式:

公式5:width=round((像素-5)/7*256 182.8571,0)

公式6:width=round((磅值*4/3-5)/7*256 182.8571,0)

说明:公式5中的像素只能是正整数,公式6中的磅值可以是小数,但小数后两位只能是下列3个数之一:25, 50, 75。

另外,Excel的列宽字符数可以设置为整数或小数,但小数后两位只支持14, 29, 43, 57, 71, 86等6个值(即使强行改为其它小数,Excel会自动改回)。通过这些值就可以把列宽精度控制到像素级别,比如4字符=33像素,4.14字符=34像素,4.29字符=35像素,4.43字符=36像素,其余类推。不想费脑筋的朋友可以使用下列python脚本生成字符数、像素和xlwt_width的对照表:

print('字符数t像素txlwt_width')for pixel in range(12, 272): chars=round((pixel-5)/7,2) width=round(chars*256 182.8571) print(f'{chars}t{pixel}t{width}')

注意上述公式和解释只适用于Excel默认字体为Arial/宋体 10磅的情形。由于xlwt使用的默认字体和字号就是Arial 10磅,所以编程时没有必要去考虑不同默认字体的情况。需要修改默认字体的朋友可以在xlwt包Formatting.py中查找Arial进行修改,然后保存即可。但不提倡修改源代码。


五、后语

虽然2018年起xlwt停止更新,且不支持目前流行的xlsx文件格式,功能更齐全的xlwings也很好用,但这个包提供的方法少而精,参数很容易理解,非常容易上手,可以很好地配合pandas进行数据格式化报表输出。在实际工作中,很多管理系统的交换文件依然采用xls格式,所以这个包还会继续受到程序员的喜爱。希望文章提出的列宽计算公式能够解决使用xlwt过程中可能遇到的小烦恼。


最新文章