openpyxl设置适应列宽 (openpyxl调整列宽)

xlrd和openpyxl是pandas用于处理Excel文件的主要依赖库,前者用于读取.xls格式文件,后者用于读写.xlsx格式文件。在使用openpyxl配合pandas生成特定格式表格文件时,经常遇到这个奇怪问题:虽然设置表格某列为X个字符宽度,但打开生成的文件查看该列宽度,往往少于X。如下图所示,第一列实际列宽比脚本设置的列宽少了0.62个字符。

如何使用openpyxl设置列宽,openpyxl调整列宽行高

列宽缩水了!

这是怎么回事呢?如何确保脚本设置的列宽和在Excel中查看的列宽相同?这需要我们首先了解Excel如何设置列宽。

一、Excel列宽知识

Excel使用字符数(VBA中用ColumnWidth读写)设置列宽,这个字符是该字体中0-9里长得最胖的那个,一般是0。如果某列宽度为10,则该列能够容纳默认字体字号的10个字符0。列宽字符数也是我们查询列宽时看到的值。

列宽像素是这样计算的:默认字体为宋体/Arial 10磅时,每个字符宽7像素,字符两侧有5像素的留白(padding),或者内边距。下面的公式更加简单明了:

列宽像素=列宽字符数*7+5

举例:如果某列宽度为10字符,则该列宽为10*7+5=75像素。

Excel还用磅(points)来表示列宽(VBA中用Width属性查看)。计算公式如下:

列宽磅数=列宽像素*3/4

默认字体字号不同,字符0的像素宽度不同,留白像素也不同。下表列出常见默认字体的情况:

默认字体

默认字号(磅)

字符宽度(像素)

留白(像素)

宋体

10

7

5

宋体

11

8

5

宋体

12

8

5

宋体

14

10

7

宋体

16

11

7

宋体

18

12

7

宋体

20

14

9

Arial

10

7

5

Arial

11

8

5

Arial

12

9

7

Arial

14

11

7

Arial

16

12

7

Arial

18

13

9

Arial

20

15

9

Calibri

10

7

5

Calibri

11

7

5

Calibri

12

8

5

Calibri

14

10

7

Calibri

16

11

7

Calibri

18

12

7

Calibri

20

14

9

微软雅黑

10

8

5

微软雅黑

11

9

7

二、openpyxl解决列宽“缩水”技巧

使用openpyxl生成.xlsx文件时,使用下列代码设置列宽:

sheet.column_dimensions['A'].width=X

这里的X表示字符数。但是在生成的.xlsx文件中,实际列宽总是“缩水”。目前没有深入研究openpyxl源代码,没有证据表明这是代码本身的缺陷。

另外,运行如下代码,可以知道openpyxl使用Calibri 11磅作为创建文件的默认字体和字号:

from openpyxl import Workbook, styles

wb=Workbook()
sheet=wb.active
default_font=styles.DEFAULT_FONT
print('default font:', default_font.name)
print('default size:', default_font.size)
sheet.save('test.xlsx')

但在Win10+Excel 2016环境下,test.xlsx的默认字体是宋体,而不是Calibri,原因未知。

如何解决这个小缺陷?可以考虑重新设置默认字体和字号,并在设置列宽时加上留白/字符宽度的比值。相当于加上了留白需要的字符数。示例代码如下:

from openpyxl import Workbook, styles
#重设默认字体和字号
styles.DEFAULT_FONT.name='宋体'
styles.DEFAULT_FONT.size=10

#新建工作簿
wb=Workbook()
sheet=wb.active
sheet.title='test'
#设置列宽为字符数+5/7(适用于默认字体为宋体/Arial 10磅)
sheet.column_dimensions['A'].width=10+5/7
wb.save('test.xlsx')

结果如下图所示:

如何使用openpyxl设置列宽,openpyxl调整列宽行高

三、总结

在实际工作中,我们经常使用pandas处理数据。虽然pandas处理数据内容的能力很强,但数据格式化输出的能力很弱,往往需要借助xlwt或openpyxl实现格式化输出。为了满足某些特定需求(比如表格套打),有时我们需要精确设置表格列宽。了解使用openpyxl设置列宽的坑以及避坑办法,可以帮助我们更好地解决精确设置表格列宽的问题。