【问题标题】:In python removing rows from a excel file using xlrd, xlwt, and xlutils在 python 中,使用 xlrd、xlwt 和 xlutils 从 excel 文件中删除行
【发布时间】:2021-12-30 08:35:21
【问题描述】:

大家好,提前谢谢大家。

我有一个 python 脚本,我在其中打开一个模板 excel 文件,添加数据(同时保留样式)并再次保存。我希望能够在保存新的 xls 文件之前删除我没有编辑的行。我的模板 xls 文件有一个页脚,所以我想删除页脚之前的多余行。

这是我加载 xls 模板的方式:

self.inBook = xlrd.open_workbook(file_path, formatting_info=True)
self.outBook = xlutils.copy.copy(self.inBook)
self.outBookCopy = xlutils.copy.copy(self.inBook)

然后我将信息写入 outBook,同时从 outBookCopy 中获取样式并将其应用于我在 outbook 中修改的每一行。

那么如何在写outBook 之前从outBook 中删除行呢?谢谢大家!

【问题讨论】:

    标签: python xls xlrd xlwt xlutils


    【解决方案1】:

    我使用 Pandas 包实现了....

    import pandas as pd
    
    #Read from Excel
    xl= pd.ExcelFile("test.xls")
    
    #Parsing Excel Sheet to DataFrame
    dfs = xl.parse(xl.sheet_names[0])
    
    #Update DataFrame as per requirement
    #(Here Removing the row from DataFrame having blank value in "Name" column)
    
    dfs = dfs[dfs['Name'] != '']
    
    #Updating the excel sheet with the updated DataFrame
    
    dfs.to_excel("test.xls",sheet_name='Sheet1',index=False)
    

    【讨论】:

      【解决方案2】:

      xlwt 没有为此提供简单的界面,但是通过直接更改工作表的行属性和行和单元格对象。

      rows 属性是一个字典,以行号为索引,因此迭代行范围需要一点小心,并且不能对其进行切片。

      鉴于您要删除的行数和您要保留的第一行的初始行号,这样的方法可能有效:

      rows_indices_to_move = range(first_kept_row, worksheet.last_used_row + 1)
      max_used_row = 0
      for row_index in rows_indices_to_move:
          new_row_number = row_index - number_to_delete
          if row_index in worksheet.rows():
              row = worksheet.rows[row_index]
              row._Row__idx = new_row_number
              for cell in row._Row__cells.values():
                  if cell:
                      cell.rowx = new_row_number
              worksheet.rows[new_row_number] = row
              max_used_row = new_row_number
          else:
              # There's no row in the block we're trying to slide up at this index, but there might be a row already present to clear out.
              if new_row_number in worksheet.rows():
                  del worksheet.rows[new_row_number]
      # now delete any remaining rows
      del worksheet.rows[new_row_number + 1:]
      # and update the internal marker for the last remaining row
      if max_used_row:
          worksheet.last_used_row = max_used_row
      

      我认为该代码中存在错误,它未经测试并且依赖于对底层数据结构的直接操作,但它应该显示总体思路。修改行和单元格对象,调整行字典,使索引正确。

      您是否在要删除的行中或在它们下方合并了范围?如果是这样,您还需要遍历工作表的 merge_ranges 属性并更新它们的行。此外,如果您要删除多组行,则需要调整此答案 - 这是特定于要删除一组行并将所有内容向上移动的情况。

      附带说明 - 我能够将文本写入我的工作表并保留预定义的样式:

      def write_with_style(ws, row, col, value):
          if ws.rows[row]._Row__cells[col]:
              old_xf_idx = ws.rows[row]._Row__cells[col].xf_idx
              ws.write(row, col, value)
              ws.rows[row]._Row__cells[col].xf_idx = old_xf_idx
          else:
              ws.write(row, col, value)
      

      这可能会让您跳过一次打开电子表格的两个副本。

      【讨论】:

      • 代码的第一行抛出:"TypeError: unhashable type: 'slice'" where: w_sheet.rows[1]
      • @Rivered - 公平点! rows 结构是一个字典而不是一个数组,只是索引整数行号。我会更新,虽然我没有方便的测试工具来确保它是正确的。这种不受支持的 API 访问总是有风险的。
      【解决方案3】:

      对于我们这些仍然坚持使用xlrd/xlwt/xlutils 的人,这里有一个filter,您可以使用:

      from xlutils.filter import BaseFilter
      
      class RowFilter(BaseFilter):
          rows_to_exclude: "Iterable[int]"
          _next_output_row: int
      
          def __init__(
                  self,
                  rows_to_exclude: "Iterable[int]",
          ):
              self.rows_to_exclude = rows_to_exclude
              self._next_output_row = -1
      
          def _should_include_row(self, rdrowx):
              return rdrowx not in self.rows_to_exclude
      
          def row(self, rdrowx, wtrowx):
              if self._should_include_row(rdrowx):
                  # Proceed with writing out the row to the output file
                  self._next_output_row += 1
                  self.next.row(
                      rdrowx, self._next_output_row,
                  )
      
          # After `row()` has been called, `cell()` is called for each cell of the row
          def cell(self, rdrowx, rdcolx, wtrowx, wtcolx):
              if self._should_include_row(rdrowx):
                  self.next.cell(
                      rdrowx, rdcolx, self._next_output_row, wtcolx,
                  )
      
      

      然后将其与 e.g. 一起使用:

      from xlrd import open_workbook
      from xlutils.filter import DirectoryWriter, XLRDReader
      
      xlutils.filter.process(
          XLRDReader(open_workbook("input_filename.xls", "output_filename.xls")),
          RowFilter([3, 4, 5]),
          DirectoryWriter("output_dir"),
      )
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-11-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-28
        • 1970-01-01
        相关资源
        最近更新 更多