Python xlwt-accès au contenu cellulaire existant, ajustement automatique de la largeur de la colonne
je suis en train d'essayer de créer un classeur Excel où je peux Auto-Définir, ou auto-ajuster les largeurs des colonnes avant de sauvegarder le classeur.
j'ai lu le Python-Excel tutoriel dans l'espoir de trouver certaines fonctions dans xlwt qui émulent xlrd (comme sheet_names()
,cellname(row, col)
, cell_type
,cell_value
, et ainsi de suite...) Par exemple, supposons que j'ai ce qui suit:
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 au rb.sheet_by_index(0)
fonction offerte dans xlrd, sauf que la première permet vous pouvez modifier le contenu (à condition que l'utilisateur a défini cell_overwrite_ok = True
)
en supposant que xlwt offre les fonctions que je cherche, j'avais l'intention de passer en revue chaque feuille de travail à nouveau, mais cette fois en gardant la trace du contenu qui prend le plus d'espace pour une colonne particulière, et en réglant la largeur de la colonne sur cette base. Bien sûr, je peux également garder la trace de la largeur maximale pour une colonne spécifique pendant que j'écris à la feuille, mais je pense qu'il serait plus propre de définir les largeurs après toutes les données a déjà été écrit.
est ce que quelqu'un sait si je peux le faire? Dans la négative, que recommandez-vous de faire pour ajuster la largeur des colonnes?
6 réponses
je viens d'implémenter une classe wrapper qui suit les largeurs des articles quand vous les entrez. Il semble fonctionner assez bien.
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)
la magie est dans John Yeung arial10
module. Cela a de bonnes largeurs pour Arial 10, qui est la police Excel par défaut. Si vous voulez écrire des feuilles de travail en utilisant d'autres polices, vous devrez changer la fonction fitwidth, idéalement en prenant en compte le style
argument passé à FitSheetWrapper.write
.
si l'on n'est pas intéressé à utiliser une autre classe (FitSheetWrapper), alors cela peut être mis en œuvre en utilisant la méthode de la colonne feuille de travail.
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 la largeur est de 2962 unités et excel la pointe à 8.11 unités. Par conséquent, je multiplie 367 à la longueur des données.
ceci est adapté de Kevins FitSheetWrapper.
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, de garder la trace de la largeur maximale au moment où vous écrivez, et de définir la largeur de la colonne à la fin, parfois après que vous avez vu toutes les données, mais avant que vous avez enregistré le cahier d'exercices.
notez que ceci l'approche la plus propre et la plus efficace disponible pour traiter les fichiers Excel. Si votre notion de "après que les données ont déjà été écrites" signifie après vous avez déjà engagé les valeurs de la 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 après que vous avez déjà sauvegardé le classeur, vous voulez le lire à nouveau pour obtenir les largeurs max, et puis le sauvegarder à nouveau avec de nouvelles largeurs de colonne, ce sera beaucoup plus lent, et nécessitera l'utilisation à la fois xlwt et xlrd (et peut-être aussi xlutils). Notez également que lorsque vous utilisez le véritable Microsoft Excel, il n'y a pas de notion de "mise à jour" d'un fichier. Il peut sembler comme cela du point de vue de l'utilisateur, mais ce qui se passe dans les coulisses est que chaque fois que vous faites une sauvegarde, Excel souffle loin le fichier existant et écrit un tout nouveau à partir de zéro.
FitSheetWrapper devrait avoir une petite modification avec xlwt3 dans 3.3.4
ligne 19:
modifier:
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 entière.
C'est peut-être un peu tard, mais j'ai créé une méthode qui fait cela pour l'ensemble feuille à la fois. C'est rapide et fait le travail. Le coussin supplémentaire param. n'est nécessaire que si vous pensez que le calcul 256 ne sera pas exact (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)
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