web-dev-qa-db-fra.com

Python xlwt - accès au contenu de la cellule existante, réglage automatique de la largeur de la colonne

J'essaie de créer un classeur Excel dans lequel je peux définir ou ajuster automatiquement la largeur des colonnes avant d'enregistrer le classeur. 

J'ai lu le didacticiel Python-Excel dans l'espoir de trouver dans xlwt des fonctions qui imitent celles xlrd (telles que sheet_names(), cellname(row, col), cell_type, cell_value, etc.). Supposons par exemple que:

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

wb.get_sheet(0) est similaire à la fonction rb.sheet_by_index(0) proposée dans xlrd, sauf que la première vous permet de modifier le contenu (à condition que l'utilisateur ait défini cell_overwrite_ok = True)

En supposant que xlwt DOES offre les fonctions que je cherchais, je prévoyais de parcourir chaque feuille de travail à nouveau, mais cette fois en gardant une trace du contenu prenant le plus de place pour une colonne particulière, et définissez la largeur de colonne en fonction de celle-ci. Bien sûr, je peux également suivre la largeur maximale d'une colonne spécifique au fur et à mesure que j'écris sur la feuille, mais j'ai l'impression que ce serait plus propre de définir les largeurs une fois que toutes les données ont été écrites.

Est-ce que quelqu'un sait si je peux faire ça? Si non, que recommanderiez-vous pour ajuster la largeur des colonnes? 

26
nooblar

Je viens d'implémenter une classe wrapper qui suit la largeur des éléments lorsque vous les entrez. Cela semble bien fonctionner.

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)

Toute la magie est dans Le module arial10 de John Yeung . Cela a de bonnes largeurs pour Arial 10, qui est la police Excel par défaut. Si vous souhaitez écrire des feuilles de calcul avec d'autres polices, vous devez modifier la fonction fitwidth, en prenant idéalement en compte l'argument style passé à FitSheetWrapper.write.

45
Kevin S

Si vous ne souhaitez pas utiliser une autre classe (FitSheetWrapper), vous pouvez le mettre en œuvre à l'aide de la méthode de colonne 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)

La valeur par défaut de width est 2962 unités et Excel la pointe à 8.11 unités. Par conséquent, je multiplie 367 en longueur de données.

Ceci est adapté de Kevins FitSheetWrapper.

5
Sravan

Il n'y a pas d'installation automatique pour cela dans xlwt. Vous devez suivre le modèle général que vous décrivez, qui consiste à garder trace de la largeur maximale en cours d’écriture et à définir la largeur de la colonne à la fin, quelque temps après avoir vu toutes les données mais avant d’avoir enregistré le classeur.

Notez que ceci est l’approche la plus propre et la plus efficace disponible lors du traitement de fichiers Excel. Si votre notion "après que les données ont déjà été écrites" signifie après que vous ayez déjà validé les valeurs de cellule ("écriture") mais avant de sauvegarder le classeur , alors la méthode décrite ci-dessus fait exactement cela. Si ce que vous voulez dire est une fois que vous avez déjà enregistré le classeur, vous souhaitez le relire pour obtenir les largeurs maximales, puis l'enregistrer à nouveau avec les nouvelles largeurs de colonne , cela sera beaucoup plus lent et nécessitera xlwt et xlrd (et éventuellement xlutils également). Notez également que lorsque vous utilisez Microsoft Excel authentique, il n’existe aucune notion de "mise à jour" d’un fichier. Cela peut sembler être le cas du point de vue de l'utilisateur, mais ce qui se passe dans les coulisses, c'est que chaque fois que vous faites une sauvegarde, Excel efface le fichier existant et en écrit un tout nouveau.

4
John Y

FitSheetWrapper devrait avoir un peu de modification avec xlwt3 dans 3.3.4

ligne 19:

changement: 

width = arial10.fitwidth(label)

à:

width = int(arial10.fitwidth(label))  

raison:\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)

la largeur doit être un entier.

1
phiree

Cela peut être un peu tard, mais j'ai créé une méthode qui le fait pour la feuille entière À la fois. C'est rapide et fait le travail. Le coussin supplémentaire n'est nécessaire que si vous pensez que le calcul 256 ne sera pas précis (si vous avez des champs de texte plus longs). 

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

j'utilise cette méthode:

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