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使用xlrd模块读写Excel文件的方法
May 06 Python
基于Python实现文件大小输出
Jan 11 Python
深入理解Python3中的http.client模块
Mar 29 Python
python爬取哈尔滨天气信息
Jul 14 Python
python内置数据类型之列表操作
Nov 12 Python
Python字典对象实现原理详解
Jul 01 Python
Django ORM多对多查询方法(自定义第三张表&amp;ManyToManyField)
Aug 09 Python
Python 写入训练日志文件并控制台输出解析
Aug 13 Python
python实现kNN算法识别手写体数字的示例代码
Aug 16 Python
python 项目目录结构设置
Feb 14 Python
Python 通过监听端口实现唯一脚本运行方式
May 05 Python
Python带参数的装饰器运行原理解析
Jun 09 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
PHP-redis中文文档介绍
2013/02/07 PHP
PHP 提取图片img标记中的任意属性的简单实例
2013/12/10 PHP
php简单复制文件的方法
2016/05/09 PHP
ThinkPHP3.2.3框架邮件发送功能图文实例详解
2019/04/23 PHP
javascript数组组合成字符串的脚本
2021/01/06 Javascript
Javascript select下拉框操作常用方法
2009/11/09 Javascript
25个好玩的JavaScript小游戏分享
2011/04/22 Javascript
学习从实践开始之jQuery插件开发 对话框插件开发
2012/04/26 Javascript
jquery实现适用于门户站的导航下拉菜单效果代码
2015/08/24 Javascript
NodeJS的Promise的用法解析
2016/05/05 NodeJs
jquery使用on绑定a标签无效 只能用live解决
2016/06/02 Javascript
JavaScript判断数字是否为质数的方法汇总
2016/06/02 Javascript
微信小程序 页面跳转传递值几种方法详解
2017/01/12 Javascript
Angularjs验证用户输入的字符串是否为日期时间
2017/06/01 Javascript
js实现登录拖拽窗口
2020/02/10 Javascript
一篇文章让你搞懂JavaScript 原型和原型链
2020/11/23 Javascript
[01:00:53]2018DOTA2亚洲邀请赛3月29日 小组赛B组 iG VS Secret
2018/03/30 DOTA
python self,cls,decorator的理解
2009/07/13 Python
Python中利用sqrt()方法进行平方根计算的教程
2015/05/15 Python
Python实现注册、登录小程序功能
2018/09/21 Python
Python3 读、写Excel文件的操作方法
2018/10/20 Python
Python实现的批量修改文件后缀名操作示例
2018/12/07 Python
用python写一个定时提醒程序的实现代码
2019/07/22 Python
python-序列解包(对可迭代元素的快速取值方法)
2019/08/24 Python
使用Python制作一个打字训练小工具
2019/10/01 Python
pytorch 彩色图像转灰度图像实例
2020/01/13 Python
html5 浏览器支持 如何让所有的浏览器都支持HTML5标签样式
2012/12/07 HTML / CSS
深入解析HTML5使用SVG图像时的viewBox属性用法
2015/09/02 HTML / CSS
为您的家、后院、车库等在线购物:Spreetail
2019/06/17 全球购物
怎样从/向数据文件读/写结构
2014/11/23 面试题
介绍一下.NET构架下remoting和webservice
2014/05/08 面试题
幼儿园优秀教师事迹
2014/02/13 职场文书
餐厅销售主管职责范本
2014/02/19 职场文书
2014年职称评定工作总结
2014/11/26 职场文书
高中教师个人总结
2015/02/10 职场文书
2016年全国助残日活动总结
2016/04/01 职场文书