web-dev-qa-db-ja.com

Python xlwt-既存のセルコンテンツへのアクセス、列幅の自動調整

ワークブックを保存する前に列の幅を自動設定または自動調整できるExcelワークブックを作成しようとしています。

私はxlrdの関数をエミュレートするxlwtの関数(sheet_names()cellname(row, col)cell_typecell_valueなど)を見つけることを期待して、Python-Excelチュートリアルを読んでいます... )たとえば、次のようなものがあるとします。

from xlwt import Workbook    
wb = Workbook()
sh1 = wb.add_sheet('sheet1' , cell_overwrite_ok = True)    
sh2 = wb.get_sheet(0)

wb.get_sheet(0)はxlrdで提供されているrb.sheet_by_index(0)関数に似ていますが、前者はコンテンツを変更できる点が異なります(ユーザーがcell_overwrite_ok = Trueを設定した場合)

Xlwt DOESが私が探している機能を提供していると仮定して、すべてのワークシートをもう一度検討することを計画していましたが、今回は特定の列で最もスペースをとるコンテンツを追跡し、それに基づいて列幅を設定します。もちろん、シートに書き込むときに特定の列の最大幅を追跡することもできますが、すべてのデータが既に書き込まれた後で幅を設定する方がわかりやすいと思います。

私がこれを行うことができるかどうか誰かが知っていますか?そうでない場合、列幅を調整するために何を行うことをお勧めしますか?

28
nooblar

入力したアイテムの幅を追跡するラッパークラスを実装しました。それはかなりうまくいくようです。

import arial10

class FitSheetWrapper(object):
    """Try to fit columns to max size of any entry.
    To use, wrap this around a worksheet returned from the 
    workbook's add_sheet method, like follows:

        sheet = FitSheetWrapper(book.add_sheet(sheet_name))

    The worksheet interface remains the same: this is a drop-in wrapper
    for auto-sizing columns.
    """
    def __init__(self, sheet):
        self.sheet = sheet
        self.widths = dict()

    def write(self, r, c, label='', *args, **kwargs):
        self.sheet.write(r, c, label, *args, **kwargs)
        width = arial10.fitwidth(label)
        if width > self.widths.get(c, 0):
            self.widths[c] = width
            self.sheet.col(c).width = width

    def __getattr__(self, attr):
        return getattr(self.sheet, attr)

すべての魔法は John Yeungのarial10モジュール にあります。これは、デフォルトのExcelフォントであるArial 10に適した幅です。他のフォントを使用してワークシートを作成する場合は、理想的にはFitSheetWrapper.writeに渡されるstyle引数を考慮して、fitwidth関数を変更する必要があります。

46
Kevin S

別のクラス(FitSheetWrapper)の使用に関心がない場合は、WorkSheet列のメソッドを使用して実装できます。

work = xlwt.WorkBook()
sheet = work.add_sheet('Sheet1')
for row_index in range(0,max_row):
   for column_index in range(0,max_col) :
      cwidth = sheet.col(column_index).width
      if (len(column_data)*367) > cwidth:  
          sheet.col(column_index).width = (len(column_data)*367) #(Modify column width to match biggest data in that column)

      sheet.write(row_index,column_index,column_data,style)

幅のデフォルト値は2962単位で、Excelはそれを8.11単位としてポイントします。したがって、データの長さに367を掛けています。

これはKevins FitSheetWrapperから採用されました。

8
Sravan

Xlwtには、このための自動機能はありません。記述している最大幅を追跡し、最後に列幅を設定する、説明した一般的なパターンに従う必要があります。すべてのデータを確認した後、ブックを保存する前のいずれかです。

このis Excelファイルを処理するときに利用できる最もクリーンで最も効率的なアプローチに注意してください。 「データがすでに書き込まれた後」という概念がセル値をすでにコミットした後(「書き込み」)が、実際にワークブックを保存する前の場合、上記の方法は正確に行われますこの。意味がワークブックを既に保存した後、もう一度読んで最大幅を取得し、新しい列幅で再度保存する場合、これはかなり遅くなります。 xlwtとxlrdの両方(およびおそらくxlutilsも)を使用する必要があります。また、正規のMicrosoft Excelを使用している場合は、ファイルを「更新」するという概念はありません。ユーザーの観点からはそのように見えるかもしれませんが、舞台裏で起こっていることは、保存を行うたびに、Excelが既存のファイルを消去し、まったく新しいファイルを最初から書き込むということです。

4
John Y

FitSheetWrapperは3.3.4のxlwt3で少し変更する必要があります

19行目:

変化する:

width = arial10.fitwidth(label)

に:

width = int(arial10.fitwidth(label))  

理由:\ Python\3.3.3\Lib\site-packages\xlwt3\biffrecords.py

1624 def __init__(self, first_col, last_col, width, xf_index, options):
1625        self._rec_data = pack('<6H', first_col, last_col, width, xf_index, options, 0)

幅は整数でなければなりません。

1
phiree

これは少し遅いかもしれませんが、シート全体に対して一度にこれを行うメソッドを作成しました。それは迅速で、仕事を成し遂げます。追加のクッションパラメータ。 256の計算が正確ではないと考える場合にのみ必要です(長いテキストフィールドがある場合)。

from xlrd import *
from xlwt import *

def autoAdjustColumns(workbook, path, writerSheet, writerSheet_index, extraCushion):
    readerSheet = open_workbook(path).sheet_by_index(writerSheet_index)
    for row in range(readerSheet.nrows):
            for column in range(readerSheet.ncols):
                    thisCell = readerSheet.cell(row, column)
                    neededWidth = int((1 + len(str(thisCell.value))) * 256) 
                    if writerSheet.col(column).width < neededWidth:
                            writerSheet.col(column).width = neededWidth + extraCushion
    workbook.save(path)
1
Connor

私はこの方法を使用します:

wb = Workbook()
ws = wb.add_sheet('Sheet1')
columnwidth = {}
row = 0
for rowdata in data:
    column = 0
    for colomndata in rowdata:
        if column in columnwidth:
            if len(colomndata) > columnwidth[column]:
                columnwidth[column] = len(colomndata)
        else:
            columnwidth[column] = len(colomndata)
        ws.write(row, column, colomndata, style0)
        column = column + 1
    row = row + 1
for column, widthvalue in columnwidth.items():
    ws.col(column).width = (widthvalue + 4) * 367
0
lxd235