Python操作Excel插入删除行的方法


Posted in Python onDecember 10, 2018

1. 前言

由于近期有任务需要,要写一个能够处理Excel的脚本,实现的功能是,在A表格上其中一列,对字符串进行分组和排序,然后根据排序好的A表格以固定格式自动填写到B表格上。

开始写脚本之前查了很多资料,最开始采用了openpyxl这个模块,用起来很顺手,使用这个对A表格其中一列进行了重新填写,但是后来发现,需要用到删除和插入空白行的操作,使用openpyxl比较困难,这个模块仅支持在表格的最后一行继续添加新行,不支持在中间插入和删除行。

在查找的过程中发现,网上流传了一些使用openpyxl进行插入删除行的操作,现整理一下。

2. 使用openpyxl

一种思路是将sheet数据转换成list,然后在list进行操作,这种方法可行,但是实际测试之后发现运行起来速度太慢了,数据1000多条,时间就已经等不起了。

# Creat insert row function group----------------------------------------------
def blankRowInsert(sheet, row_num, add_num):
  myList = Sheet2List(sheet)
  insertLine(myList, row_num, add_num, sheet.max_column)
  List2Sheet(sheet,myList)

def Sheet2List(sheet):
  # 把一个表格中的数据全部导出到一个列表
  listResult = []
  for i in range(1,sheet.max_row + 1):
    lineData = []
    for j in range(1,sheet.max_column +1):
      cell = sheet.cell(row = i, column = j)
      lineData.append(cell.value)
    listResult.append(lineData)
  return listResult

def insertLine(aList, row_num , add_num, maxColumn):
  # 对列表进行添加操作操作
  for _ in range(1,add_num + 1):
    # ['']*N是创建一个个数为N的空格列表,插入列表aList
    aList.insert(row_num, [''] * maxColumn)

def List2Sheet(sheet,list):
  # 把数据写回sheet
  for i in range(1, len(list) + 1):
    for j in range(1, len(list[0]) + 1):
      cell = sheet.cell(row=i, column=j)
      cell.value = list[i-1][j-1]
# End of insert row function group---------------------------------------------

另外一种思路是直接自己给openpyxl这个轮子补胎,添加一个新的方法,笔者没有试验,下面的代码是StackOverflow相关问题上面贴的,如果各位有兴趣可以自己尝试。

def insert_rows(self, row_idx, cnt, above=False, copy_style=True, fill_formulae=True):
  """Inserts new (empty) rows into worksheet at specified row index.

  :param row_idx: Row index specifying where to insert new rows.
  :param cnt: Number of rows to insert.
  :param above: Set True to insert rows above specified row index.
  :param copy_style: Set True if new rows should copy style of immediately above row.
  :param fill_formulae: Set True if new rows should take on formula from immediately above row, filled with references new to rows.

  Usage:

  * insert_rows(2, 10, above=True, copy_style=False)

  """
  CELL_RE = re.compile("(?P<col>\$?[A-Z]+)(?P<row>\$?\d+)")

  row_idx = row_idx - 1 if above else row_idx

  def replace(m):
    row = m.group('row')
    prefix = "$" if row.find("$") != -1 else ""
    row = int(row.replace("$",""))
    row += cnt if row > row_idx else 0
    return m.group('col') + prefix + str(row)

  # First, we shift all cells down cnt rows...
  old_cells = set()
  old_fas  = set()
  new_cells = dict()
  new_fas  = dict()
  for c in self._cells.values():

    old_coor = c.coordinate

    # Shift all references to anything below row_idx
    if c.data_type == Cell.TYPE_FORMULA:
      c.value = CELL_RE.sub(
        replace,
        c.value
      )
      # Here, we need to properly update the formula references to reflect new row indices
      if old_coor in self.formula_attributes and 'ref' in self.formula_attributes[old_coor]:
        self.formula_attributes[old_coor]['ref'] = CELL_RE.sub(
          replace,
          self.formula_attributes[old_coor]['ref']
        )

    # Do the magic to set up our actual shift  
    if c.row > row_idx:
      old_coor = c.coordinate
      old_cells.add((c.row,c.col_idx))
      c.row += cnt
      new_cells[(c.row,c.col_idx)] = c
      if old_coor in self.formula_attributes:
        old_fas.add(old_coor)
        fa = self.formula_attributes[old_coor].copy()
        new_fas[c.coordinate] = fa

  for coor in old_cells:
    del self._cells[coor]
  self._cells.update(new_cells)

  for fa in old_fas:
    del self.formula_attributes[fa]
  self.formula_attributes.update(new_fas)

  # Next, we need to shift all the Row Dimensions below our new rows down by cnt...
  for row in range(len(self.row_dimensions)-1+cnt,row_idx+cnt,-1):
    new_rd = copy.copy(self.row_dimensions[row-cnt])
    new_rd.index = row
    self.row_dimensions[row] = new_rd
    del self.row_dimensions[row-cnt]

  # Now, create our new rows, with all the pretty cells
  row_idx += 1
  for row in range(row_idx,row_idx+cnt):
    # Create a Row Dimension for our new row
    new_rd = copy.copy(self.row_dimensions[row-1])
    new_rd.index = row
    self.row_dimensions[row] = new_rd
    for col in range(1,self.max_column):
      col = get_column_letter(col)
      cell = self.cell('%s%d'%(col,row))
      cell.value = None
      source = self.cell('%s%d'%(col,row-1))
      if copy_style:
        cell.number_format = source.number_format
        cell.font   = source.font.copy()
        cell.alignment = source.alignment.copy()
        cell.border  = source.border.copy()
        cell.fill   = source.fill.copy()
      if fill_formulae and source.data_type == Cell.TYPE_FORMULA:
        s_coor = source.coordinate
        if s_coor in self.formula_attributes and 'ref' not in self.formula_attributes[s_coor]:
          fa = self.formula_attributes[s_coor].copy()
          self.formula_attributes[cell.coordinate] = fa
        # print("Copying formula from cell %s%d to %s%d"%(col,row-1,col,row))
        cell.value = re.sub(
          "(\$?[A-Z]{1,3}\$?)%d"%(row - 1),
          lambda m: m.group(1) + str(row),
          source.value
        )
        cell.data_type = Cell.TYPE_FORMULA

  # Check for Merged Cell Ranges that need to be expanded to contain new cells
  for cr_idx, cr in enumerate(self.merged_cell_ranges):
    self.merged_cell_ranges[cr_idx] = CELL_RE.sub(
      replace,
      cr
    )

# Use way:
# Worksheet.insert_rows = insert_rows

3. 使用xlwings

进行一些列尝试和折腾之后,笔者放弃了使用openpyxl操作Excel插入和删除行了,到网上寻觅,发现了xlwings这个轮子,说明里写有api能够调用VBA的函数,这就很炫酷了,然后翻了翻文档,决定使用这个轮子操作,现贴出来笔者写的几段代码作为使用方法示范。

3.1. 删除行: range.api.EntireRow.Delete()

# Delete origin row
temp_del = 0
if len(delete_list) > 0:
  for delete_row in delete_list:
    # Report schedule
    print("Have alerady done: " + \
        str((temp_del*100)//delete_num) + "%")
    # Delete one row
    wb_sheet.range('A'+str(delete_row-temp_del)).api.EntireRow.Delete()
    temp_del = temp_del + 1
wb.save()

上面这段代码使用了一些小技巧,delete_list储存的是原表格中,需要删除的行号,在删除过程中由于总行数也在跟着减少,所以需要把绝对行号转成相对行号进行标记删除,这个转换就是temp_del变量的使用目的。

3.2. 插入行: sheet.api.Rows(row_number).Insert()

if key_word == sheet.range('A'+str(i_row+1)).value:
  # Insert new line
  sheet.api.Rows(i_row+2).Insert()

需要注意的是,这个VBA函数是向上插入空行,并且xlwings这个轮子只能在windows和macos的系统下使用,暂时不支持Linux。不过xlwings运行速度要远超过openpyxl,而且还能直接调用VBA的函数,对于WPS和Excel都能兼容,综合来看,还是选择xlwings比较好一些。

以上这篇Python操作Excel插入删除行的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
初步解析Python下的多进程编程
Apr 28 Python
python中assert用法实例分析
Apr 30 Python
python制作企业邮箱的爆破脚本
Oct 05 Python
Python下的Softmax回归函数的实现方法(推荐)
Jan 26 Python
详谈Python2.6和Python3.0中对除法操作的异同
Apr 28 Python
浅析使用Python操作文件
Jul 31 Python
Python Pandas 获取列匹配特定值的行的索引问题
Jul 01 Python
python GUI库图形界面开发之PyQt5信号与槽事件处理机制详细介绍与实例解析
Mar 08 Python
Python偏函数Partial function使用方法实例详解
Jun 17 Python
python使用列表的最佳方案
Aug 12 Python
Python 中如何写注释
Aug 28 Python
OpenCV3.3+Python3.6实现图片高斯模糊
May 18 Python
Python openpyxl 遍历所有sheet 查找特定字符串的方法
Dec 10 #Python
使用pandas实现csv/excel sheet互相转换的方法
Dec 10 #Python
python得到一个excel的全部sheet标签值方法
Dec 10 #Python
解决pandas .to_excel不覆盖已有sheet的问题
Dec 10 #Python
python模块导入的细节详解
Dec 10 #Python
pandas每次多Sheet写入文件的方法
Dec 10 #Python
Python用61行代码实现图片像素化的示例代码
Dec 10 #Python
You might like
实现 win2003 下 mysql 数据库每天自动备份
2006/12/06 PHP
检测png图片是否完整的php代码
2010/09/06 PHP
ubuntu下编译安装xcache for php5.3 的具体操作步骤
2013/06/18 PHP
使用Jquery Aajx访问WCF服务(GET、POST、PUT、DELETE)
2012/03/16 Javascript
jQuery Tools tab使用介绍
2012/07/14 Javascript
用按钮控制iframe显示的网页实现方法
2013/02/04 Javascript
页面右下角弹出提示框示例代码js版
2013/08/02 Javascript
JS 有趣的eval优化输入验证实例代码
2013/09/22 Javascript
Jquery判断$(&quot;#id&quot;)获取的对象是否存在的方法
2013/09/25 Javascript
jQuery实现限制textarea文本框输入字符数量的方法
2015/05/28 Javascript
探究Javascript模板引擎mustache.js使用方法
2016/01/26 Javascript
jquery自定义右键菜单、全选、不连续选择
2016/03/01 Javascript
JQuery的常用选择器、过滤器、方法全面介绍
2016/05/25 Javascript
js利用for in循环获取 一个对象的所有属性以及值的实例
2017/03/30 Javascript
vue实现的微信机器人聊天功能案例【附源码下载】
2019/02/18 Javascript
python通过imaplib模块读取gmail里邮件的方法
2015/05/08 Python
python日志记录模块实例及改进
2017/02/12 Python
Python 的类、继承和多态详解
2017/07/16 Python
运用TensorFlow进行简单实现线性回归、梯度下降示例
2018/03/05 Python
Python读取Pickle文件信息并计算与当前时间间隔的方法分析
2019/01/30 Python
Pytorch 抽取vgg各层并进行定制化处理的方法
2019/08/20 Python
Anaconda的安装与虚拟环境建立
2020/11/18 Python
纽约州一群才华横溢的金匠制作而成:Hearth Jewelry
2019/03/22 全球购物
德国珠宝和手表在线商店:VALMANO
2019/03/24 全球购物
医院学雷锋活动策划方案
2014/02/15 职场文书
数控机床专业自荐信
2014/05/19 职场文书
施工安全承诺书
2014/05/22 职场文书
幼儿发展评估方案
2014/06/11 职场文书
应届生求职信范文
2014/06/30 职场文书
班子查摆四风个人对照检查材料思想汇报
2014/10/04 职场文书
售后服务承诺函格式
2015/01/21 职场文书
2015学校六五普法工作总结
2015/04/22 职场文书
加薪申请报告范本
2015/05/15 职场文书
2015年党务公开工作总结
2015/05/19 职场文书
MYSQL 的10大经典优化案例场景实战
2021/09/14 MySQL
使用 DataAnt 监控 Apache APISIX的原理解析
2022/07/07 Servers