问题
I am trying to move a cell range inside a worksheet using Python 2.7 + openpyxl. What seemed to be an easy and basic task turned out to be close to impossible. Here is how I'd like it to look in Excel:
To make the task easier let's assume I only need to move range from given cell to the end of data (to last row and column). My first idea was easy:
for i, column in enumerate(columns):
if i >= starting_col:
for j, cell in enumerate(column):
if j >= starting_row:
copy_cell(ws, j+1, i+1, j+1, i+movement)
But hey, what how to efficiently and fully realize copy_cell
?
By trial and error I managed to come to 4 things I need to copy:
- Value
- Style
- Hyperlinks
- Number format
It didn't work quite as I expected - most of cells are copied properly but hyperlinks don't seem to work, copying .style attribute didn't work either (hence my try to access _style which worked) and my worst problem appeared - merged cell ranged. How to deal with them? My copy_cell()
looks like this at the moment:
def copy_cell(ws, from_row, from_col, to_row, to_col):
# first value
ws.cell(row=to_row, column=to_col).value = ws.cell(row=from_row, column=from_col).value
# second formatting
from_style = ws.cell(row=from_row, column=from_col)._style
ws.cell(row=to_row, column=to_col)._style = from_style
ws.cell(row=to_row, column=to_col).hyperlink = ws.cell(row=from_row, column=from_col).hyperlink
ws.cell(row=to_row, column=to_col).number_format = ws.cell(row=from_row, column=from_col).number_format
Isn't there a better, generic way to copy whole cell range? Or at least whole cell with all of its attributes? If not, maybe there is an efficient way to move or copy merged cell ranges?
回答1:
The following methods work for me, you can also specify a different worksheet:
from copy import copy
def copy_cell(source_cell, coord, tgt):
tgt[coord].value = source_cell.value
if source_cell.has_style:
tgt[coord]._style = copy(source_cell._style)
return tgt[coord]
You can call it with the following:
copy_cell(worksheet['E6'], 'D11', worksheet)
Or if you instead need to move a cell, you can do this:
def move_cell(source_cell, coord, tgt):
tgt[coord].value = source_cell.value
if source_cell.has_style:
tgt[coord]._style = copy(source_cell._style)
del source_cell.parent._cells[(source_cell.row, source_cell.col_idx)]
return tgt[coord]
Nevertheless, notice that the merge cells have to be done separatedly.
回答2:
I have built this method to copy cells without touching their contents:
def move_cell(source_cell, dest_row, dest_col, preserve_original=False):
"""
:param source_cell: cell to be moved to new coordinates
:param dest_row: 1-indexed destination row
:param dest_col: 1-indexed destination column
:param preserve_original: if True, does a copy instead of a move
"""
if preserve_original:
cell_to_move = copy.copy(source_cell)
else:
cell_to_move = source_cell
worksheet = cell_to_move.parent
source_address = (cell_to_move.row, cell_to_move.col_idx)
dest_address = (dest_row, dest_col)
cell_to_move.row = dest_row
cell_to_move.col_idx = dest_col
worksheet._cells[dest_address] = cell_to_move
if not preserve_original:
del worksheet._cells[source_address]
return cell_to_move
来源:https://stackoverflow.com/questions/45347284/in-openpyxl-how-to-move-or-copy-a-cell-range-with-formatting-merged-cells-for