我有以下脚本将CSV文件转换为XLSX文件,但我的列大小非常窄。每次我用鼠标拖动它们来读取数据。有人知道如何在openpyxl
中设置列宽吗?
这是我正在使用的代码。
#!/usr/bin/python2.6
import csv
from openpyxl import Workbook
from openpyxl.cell import get_column_letter
f = open('users_info_cvs.txt', "rU")
csv.register_dialect('colons', delimiter=':')
reader = csv.reader(f, dialect='colons')
wb = Workbook()
dest_filename = r"account_info.xlsx"
ws = wb.worksheets[0]
ws.title = "Users Account Information"
for row_index, row in enumerate(reader):
for column_index, cell in enumerate(row):
column_letter = get_column_letter((column_index + 1))
ws.cell('%s%s'%(column_letter, (row_index + 1))).value = cell
wb.save(filename = dest_filename)
答案 0 :(得分:61)
您可以估算(或使用单声道宽度字体)来实现此目的。我们假设数据是一个嵌套数组,如[['a1','a2'],['b1','b2']]
我们可以获得每列中的最大字符数。然后将宽度设置为。宽度恰好是等宽字体的宽度(如果不至少更改其他样式)。即使你使用可变宽度字体,这也是一个不错的估计。这不适用于公式。
column_widths = []
for row in data:
for i, cell in enumerate(row):
if len(column_widths) > i:
if len(cell) > column_widths[i]:
column_widths[i] = len(cell)
else:
column_widths += [len(cell)]
for i, column_width in enumerate(column_widths):
worksheet.column_dimensions[get_column_letter(i+1)].width = column_width
有点黑客但你的报告会更具可读性。
答案 1 :(得分:28)
我对Bufke的回答有所不同。避免使用数组进行一些分支并忽略空单元格/列。
现已修复非字符串单元格值。
ws = your current worksheet
dims = {}
for row in ws.rows:
for cell in row:
if cell.value:
dims[cell.column] = max((dims.get(cell.column, 0), len(str(cell.value))))
for col, value in dims.items():
ws.column_dimensions[col].width = value
答案 2 :(得分:25)
设置至少在openpyxl版本2.4.0中工作的所有列的宽度的更加pythonic方式:
for column_cells in worksheet.columns:
length = max(len(as_text(cell.value)) for cell in column_cells)
worksheet.column_dimensions[column_cells[0].column].width = length
as_text函数应该是将值转换为适当长度的字符串,就像Python 3一样:
def as_text(value):
if value is None:
return ""
return str(value)
答案 3 :(得分:6)
我有一个merged_cells的问题,自动调整不能正常工作,如果你遇到同样的问题,可以用下一个代码解决:
for col in worksheet.columns:
max_length = 0
column = col[0].column # Get the column name
for cell in col:
if cell.coordinate in worksheet.merged_cells: # not check merge_cells
continue
try: # Necessary to avoid error on empty cells
if len(str(cell.value)) > max_length:
max_length = len(cell.value)
except:
pass
adjusted_width = (max_length + 2) * 1.2
worksheet.column_dimensions[column].width = adjusted_width
答案 4 :(得分:5)
对于openpyxl 3.0.3,修改列的最佳方法是使用DimensionHolder对象,该对象是将每列映射到ColumnDimension对象的字典。
ColumnDimension可以获取参数bestFit,auto_size(bestFit的别名)和width。
就个人而言,auto_size不能按预期工作,我不得不使用width并弄清楚该列的最佳宽度是len(cell_value) * 1.23
。
要获得每个单元格的值,有必要遍历每个单元格,但是我个人没有使用它,因为在我的项目中我只需要编写工作表,因此我直接在数据上获得了每一列中最长的字符串
下面的示例仅显示如何修改列尺寸:
import openpyxl
from openpyxl.worksheet.dimensions import ColumnDimension, DimensionHolder
from openpyxl.utils import get_column_letter
wb = openpyxl.load_workbook("Example.xslx")
ws = wb["Sheet1"]
dim_holder = DimensionHolder(worksheet=ws)
for col in range(ws.min_column, ws.max_column + 1):
dim_holder[get_column_letter(col)] = ColumnDimension(ws, min=col, max=col, width=20)
ws.column_dimensions = dim_holder
答案 5 :(得分:3)
上述公认的答案略有改进,我认为更加pythonic(要求宽恕比要求许可更好)
column_widths = []
for row in workSheet.iter_rows():
for i, cell in enumerate(row):
try:
column_widths[i] = max(column_widths[i], len(cell.value))
except IndexError:
column_widths.append(len(cell.value))
for i, column_width in enumerate(column_widths):
workSheet.column_dimensions[get_column_letter(i + 1)].width = column_width
答案 6 :(得分:2)
当openpxyl更新时,我不得不更改以上答案的@ User3759685。我遇到了错误。 @phihag也在评论中报告了这一点
for column_cells in ws.columns:
new_column_length = max(len(as_text(cell.value)) for cell in column_cells)
new_column_letter = (openpyxl.utils.get_column_letter(column_cells[0].column))
if new_column_length > 0:
ws.column_dimensions[new_column_letter].width = new_column_length + 1
答案 7 :(得分:1)
这是Python 3.8和OpenPyXL 3.0.0的答案。
我试图避免使用get_column_letter
函数,但是失败了。
此解决方案使用了新引入的assignment expressions又名“海象运算符”:
import openpyxl
from openpyxl.utils import get_column_letter
workbook = openpyxl.load_workbook("myxlfile.xlsx")
worksheet = workbook["Sheet1"]
MIN_WIDTH = 10
for i, column_cells in enumerate(worksheet.columns, start=1):
width = (
length
if (length := max(len(str(cell_value) if (cell_value := cell.value) is not None else "")
for cell in column_cells)) >= MIN_WIDTH
else MIN_WIDTH
)
worksheet.column_dimensions[get_column_letter(i)].width = width
答案 8 :(得分:1)
从openpyxl2.5.2a更新到最新的2.6.4(支持python 2.x的最终版本)后,在配置列宽时遇到了同样的问题。
基本上,我总是计算一列的宽度(昏暗是维持每一列宽度的命令):
dims[cell.column] = max((dims.get(cell.column, 0), len(str(cell.value))))
此后,我将比例尺修改为比原始大小稍大一些的东西,但是现在您必须给列的“ Letter”值而不是int值(col在下面是该值,并转换为正确的字母) ):
worksheet.column_dimensions[get_column_letter(col)].width = value +1
这将纠正可见错误并为您的列分配正确的宽度;) 希望有帮助。
答案 9 :(得分:1)
这是我的版本,引用了@Virako的代码段
def adjust_column_width_from_col(ws, min_row, min_col, max_col):
column_widths = []
for i, col in \
enumerate(
ws.iter_cols(min_col=min_col, max_col=max_col, min_row=min_row)
):
for cell in col:
value = cell.value
if value is not None:
if isinstance(value, str) is False:
value = str(value)
try:
column_widths[i] = max(column_widths[i], len(value))
except IndexError:
column_widths.append(len(value))
for i, width in enumerate(column_widths):
col_name = get_column_letter(min_col + i)
value = column_widths[i] + 2
ws.column_dimensions[col_name].width = value
使用方法如下
adjust_column_width_from_col(ws, 1,1, ws.max_column)
答案 10 :(得分:1)
我制作了一个处理大型 Excel 文件非常快的函数,因为它使用了 pandas.read_excel
import pandas as pd
from openpyxl import load_workbook
from openpyxl.utils import get_column_letter
def auto_adjust_column_width(file_path, sheet_name=0):
column_widths = []
df = pd.read_excel(file_path, sheet_name=sheet_name, header=None)
for col in df.columns:
max_length = int(df[col].astype(str).str.len().max() * 1.2)
column_widths.append(max_length)
wb = load_workbook(file_path)
if isinstance(sheet_name, int):
sheet_name = wb.sheetnames[sheet_name]
worksheet = wb[sheet_name]
for i, column_width in enumerate(column_widths):
column = get_column_letter(i+1)
worksheet.column_dimensions[column].width = column_width
wb.save(file_path)
答案 11 :(得分:0)
我们可以将数字转换为其ASCII值,并将其提供给column_dimension参数
\b[a-z0-9-,)(]+\b
答案 12 :(得分:0)
以上所有答案均产生一个问题,即col [0] .column返回数字,而worksheet.column_dimensions [column]仅接受诸如'A','B','C'之类的字符代替列。我已经修改了@Virako的代码,现在可以正常使用了。
import re
import openpyxl
..
for col in _ws.columns:
max_lenght = 0
print(col[0])
col_name = re.findall('\w\d', str(col[0]))
col_name = col_name[0]
col_name = re.findall('\w', str(col_name))[0]
print(col_name)
for cell in col:
try:
if len(str(cell.value)) > max_lenght:
max_lenght = len(cell.value)
except:
pass
adjusted_width = (max_lenght+2)
_ws.column_dimensions[col_name].width = adjusted_width
答案 13 :(得分:0)
这是一个肮脏的修复程序。但是openpyxl实际上支持auto_fit
。但是没有方法可以访问该属性。
import openpyxl
from openpyxl.utils import get_column_letter
wb = openpyxl.load_workbook("Example.xslx")
ws = wb["Sheet1"]
for i in range(1, ws.max_column+1):
ws.column_dimensions[get_column_letter(i)].bestFit = True
ws.column_dimensions[get_column_letter(i)].auto_size = True
答案 14 :(得分:0)
从openpyxl 2.6.1开始,设置宽度时需要列字母,而不是列号。
for column in sheet.columns:
length = max(len(str(cell.value)) for cell in column)
length = length if length <= 16 else 16
sheet.column_dimensions[column[0].column_letter].width = length
答案 15 :(得分:0)
当我遇到这个问题时,我只是用 openpyxl 做我想做的一切,保存工作簿,然后用 pywin32 再次打开它。 Pywin32 内置了 autofit,无需制定一堆规则/条件。
from win32com.client import Dispatch
excel = Dispatch('Excel.Application')
wb = excel.Workbooks.Open("excelFile.xlsx")
excel.Worksheets(1).Activate()
excel.ActiveSheet.Columns.AutoFit()
wb.Save()
wb.Close()
excel.Quit()
不过,我确实添加了一条规则,因为我有一个文本列,其中包含一些不需要显示的长值。我将任何列限制为 75 个字符。
excel = Dispatch('Excel.Application')
wb = excel.Workbooks.Open("excelFile.xlsx")
excel.Worksheets(1).Activate()
excel.ActiveSheet.Columns.AutoFit()
for col in excel.ActiveSheet.Columns:
if col.ColumnWidth > 75:
col.ColumnWidth = 75
wb.Save()
wb.Close()
excel.Quit()
答案 16 :(得分:0)
编译并应用上述多个建议,并将合并单元格检测扩展到仅水平合并单元格,我可以提供以下代码:
def adjust_width(ws):
"""
Adjust width of the columns
@param ws: worksheet
@return: None
"""
def is_merged_horizontally(cell):
"""
Checks if cell is merged horizontally with an another cell
@param cell: cell to check
@return: True if cell is merged horizontally with an another cell, else False
"""
cell_coor = cell.coordinate
if cell_coor not in ws.merged_cells:
return False
for rng in ws.merged_cells.ranges:
if cell_coor in rng and len(list(rng.cols)) > 1:
return True
return False
for col_number, col in enumerate(ws.columns, start=1):
col_letter = get_column_letter(col_number)
max_length = max(
len(str(cell.value or "")) for cell in col if not is_merged_horizontally(cell)
)
adjusted_width = (max_length + 2) * 0.95
ws.column_dimensions[col_letter].width = adjusted_width