Python操作Excel插入删除行

2023-11-03

Python操作Excel插入删除行

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比较好一些。


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python操作Excel插入删除行 的相关文章

随机推荐

  • iphone投屏ipad_手机无线投屏到电脑

    无线投屏顾名思义就是通过无线方式将图片 音频 视频内容输出到另一个设备 显示屏 音响等 上 常见的场景就是将手机屏幕投屏到另一个显示屏上 无线投屏由于摆脱了各种拓展坞 连接线的束缚 因而使人们享受更便捷 更自由的投屏体验 本文主要介绍Mir
  • 并发编程(五)——线程池及原理剖析

    前言 欢迎大家一起来学习多线程 大家一起来学习吧 并发编程 一 多线程快速入门 并发编程 二 内存模型 并发编程 三 多线程之间如何实现通讯 并发编程 四 JUC并发包常用方法介绍 并发编程 五 线程池及原理剖析 并发编程 六 java中锁
  • 解决sourceTree拉取和推送代码到bitBucket时一直弹出输入密码对话框

    在使用sourceTree pull和push代码时一直出现提示输入密码的弹出框 每一次输入密码并勾选让他保存用户密码 等到第二次操作时还是会出现这种弹出框 扰乱思路与视线 而且他还会在push代码时出现提示错误 无效的用户名和密码 这和前
  • 计蒜客T1236——分苹果

    今天分享一道特别简单的题 根据题意 不难看出 如果要求最少的苹果个数 则第一个小朋友需要给得最少 即1个 之后每个人多一个 既满足了不同于之前的所有人 还能满足最少的条件 所以 只需要将1 n依次累加 即可满足目标条件 include
  • 【问题记录】02 Linux服务器安装MySql数据库报错:Failing package is: mysql-community-server GPG Keys are configured as

    1 报错信息如下 warning var cache yum x86 64 7 mysql57 community packages mysql community server 5 7 37 1 el7 x86 64 rpm Header
  • Windows系统版本宏_WIN32_WINNT对应值

    win7 WIN32 WINNT gt 0x0601 vista WIN32 WINNT gt 0x0600 Windows XP WIN32 WINNT gt 0x0501 Windows 2000 WIN32 WINNT gt 0x05
  • 如何修改maven本地仓库地址

    1 如果从未配置过本地仓库 那么默认的仓库文件夹应该是在user gt admin 或者管理员名字命名的文件夹 gt m2 gt repository 仓库文件夹 将文件挪动到maven文件夹下 当然 这么做的是因为仓库中有之前保留的很多j
  • obsidian插件无法加载的解决办法

    1 问题 插件安装 但启动不了 2 解决方案 1 去obsidian插件官网搜索 2 下载以下3个文件 到 obsidian plugin目录下 路径 F 2023年 obsidian plugins cMenu 1 1 1 3 进入obs
  • docker 安装gitlab血泪史(解决方式telnet查看未开通端口号)

    1 docker pull gitlab gitlab ce 2 执行 docker run d p 443 443 p 80 80 p 222 22 name gitlab restart always v home gitlab con
  • 图像语义分割python_图像语义分割ICNET_飞桨-源于产业实践的开源深度学习平台...

    图像语义分割 ICNET 类别 智能视觉 PaddleCV 应用 自动驾驶 室内导航 医学图像诊断 穿戴设备 虚拟现实与增强现实 无人机 模型概述 ICNet 主要用于图像实时语义分割 能够兼顾速度和准确性 ICNet的主要思想是将输入图像
  • mysql hash分区要点

    mysql 有很多种表分区的方式 这里写一些笔者对于hash分区的感悟 如有错误 恳请读者斧正 mysql hash分区不用像其他的分区指定 当某一列值得情况为某某某的情况去到某一分区 比如list分区和range分区 hash直接只用指定
  • My eclipse 无法打开workspace解决方案

    今天用myeclipse的时候试图引用code comment style 在引用的过程中死掉了 就杀死进程 myeclipse提示crash 再打开次workspace 就一直处于 loading workbench 状态 打开其他wor
  • 进程和线程的区别

    进程 Process 和线程 Thread 是操作系统中的两个重要概念 它们是实现多任务并发执行的两种方式 它们有以下主要区别 1 定义和资源 进程 进程是正在运行的程序的实例 拥有独立的地址空间和资源 每个进程都有自己的代码 数据 堆栈
  • Windows11 拒绝访问压缩(zipped)文件夹

    最近windows10被自动升级到windows11 使用的一个工具zip压缩包突然就无法解压了 提示 拒绝访问压缩 zipped 文件夹 提取文件之前 必须更改这个压缩文件夹的权限 我的尝试 更改了这个压缩包文件的属性中的各个用户权限 增
  • 数字图像处理 基于python读取DICOM、NIfTI格式医学图像文件

    一 医学图像 医学图像标注最重要的进步之一是应用机器学习来评估图像 以实现更精确 更快 更准确的医学诊断 在应用机器学习 ML 人工智能 AI 或任何其他诊断算法之前 您需要知道注释软件可以处理两种最常见的医疗和保健图像文件格式 包括 DI
  • SpringBoot如何避免SQL注入漏洞呢?

    转自 SpringBoot如何避免SQL注入漏洞呢 下文笔者讲述SpringBoot避免SQL注入漏洞的方法分享 如下所示 SQL盲注 SQL注入简介 SQL注入的风险 数据库中的数据被任意查看 修改 删除 SQL注入的原因 未对用户输入进
  • mysql的驱动connect放在哪里_MySQL文档阅读笔记之JDBC驱动参数autoReconnect的副作用...

    MySQL的特性之一可高度定制化 相应的MySQL提供的JDBC驱动也提供了相当多的参数 老实说 第一次阅读文档时 真心晕 不过还是禁不住的赞叹 MySQL的JDBC驱动都有茫茫多的参数 果然有特点 这些参数中autoReconnect吸引
  • 无注册中心使用dubbo

    前言 熟悉dubbo的朋友都知道 dubbo可通过指定Url方式绕过注册中心直连指定的服务地址 所以想当然会想到那么可不可以不使用注册中心 本文就是SpringBoot整合Dubbo 无注册中心 的示例展示 提供者dubbo provide
  • Cobar使用文档(可用作MySQL大型集群解决方案)

    Cobar使用文档 可用作MySQL大型集群解决方案 2013 12 11 16 06 17236人阅读 评论 0 收藏 举报 分类 cobar 1 转 http blog csdn net shagoo article details 8
  • Python操作Excel插入删除行

    Python操作Excel插入删除行 1 前言 2 使用openpyxl 3 使用xlwings 3 1 删除行 range api EntireRow Delete 3 2 插入行 sheet api Rows row number In