zqzgjqR 2023-07-14 18:11 采纳率: 0%
浏览 7

用VBA还是python解决

img

用VBA还是python解决,怎么简化这个逻辑。怎么编写比较通常。

img


如果最后一行的值再另一个表格内,怎么匹配后再自动化

  • 写回答

1条回答 默认 最新

  • CSDN-Ada助手 CSDN-AI 官方账号 2023-07-14 20:32
    关注
    • 这有个类似的问题, 你可以参考下: https://ask.csdn.net/questions/7654629
    • 你也可以参考下这篇文章:用Excel表达图片如何由像素点构成 - python+VBA方式
    • 除此之外, 这篇博客: VBA代码翻译成Python调用示例中的 VBA代码翻译成Python调用示例 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
    • 下面这段拆分Excel表的vba代码来自才哥的文章《Python对比VBA实现excel表格合并与拆分》,作者“两百斤的老涛”:

      Sub 表格拆分()
          '屏幕刷新=false
          Application.ScreenUpdating = False
          Dim LastRow, LastCol As Long
          Dim Sh, Sht As Worksheet
          'Sh指代当前活动页
          Set Sh = ActiveSheet
          '当前活动页的最后一行
          LastRow = Sh.Cells(Rows.Count, 1).End(xlUp).Row
          '当前活动页的最后一列
          LastCol = Sh.Cells(1, Columns.Count).End(xlToLeft).Column
          '定义D为字典
          Dim D As Object
          Set D = CreateObject("Scripting.Dictionary")
          Dim Col As Integer
          'Col为要手动输入要拆分的列序数
          Col = InputBox("输入用于分组的列序号!")
          '从第2行找到最后一行
          For i = 2 To LastRow
              '查找这个要拆分行,看它在不在字典里
              TempStr = CStr(Sh.Cells(i, Col))
              '如果在字典里
              If D.exists(TempStr) Then
                  '将数据放到对应的页里
                  Set Sht = Worksheets(TempStr)
                  '字典key值对应的项目值记录该页当前内容添加的行数,每次+1
                  D(TempStr) = D(TempStr) + 1
                  '下面一行可以注释掉了跟下面的重复了……
                  'Sht.Cells(D(TempStr), 1) = Sh.Cells(i, 1)
                  For j = 1 To LastCol
                      Sht.Cells(D(TempStr), j) = Sh.Cells(i, j)
                  Next
              Else
                  '如果不在字典里,就添加一个新key
                  D.Add TempStr, 1
                  'i = i - 1是让该行一会儿重新检索一遍就能进到if里了
                  i = i - 1
                  '在最后一页新加一页,页名就是TempStr
                  Sheets.Add After:=Sheets(Sheets.Count)
                  Sheets(Sheets.Count).Name = TempStr
                  '下面一行也是可以注释掉的
                  'Sheets(Sheets.Count).Cells(1, 1) = Sh.Cells(1, 1)
                  '把第一行标题行弄过去
                  For j = 1 To LastCol
                      Sheets(Sheets.Count).Cells(1, j) = Sh.Cells(1, j)
                  Next
              End If
          Next
          '激活初始页,视觉上保持不变
          Sh.Activate
          'RT,GDCDSZ
          MsgBox ("完成!")
      
      End Sub
      

      下面我们将其转换为python代码来调用:

      建立在已经打开Excel文件的前提下:

      import win32com.client as win32  # 导入模块
      import os
      
      excel_app = win32.gencache.EnsureDispatch('Excel.Application')
      
      filename = "数据源.xlsx"
      filename = os.path.abspath(filename)
      
      wb = excel_app.Workbooks.Open(filename)
      

      Set Sh = ActiveSheet等价于:

      Sh = wb.ActiveSheet
      

      对于下面这两行代码:

      '当前活动页的最后一行
      LastRow = Sh.Cells(Rows.Count, 1).End(xlUp).Row
      '当前活动页的最后一列
      LastCol = Sh.Cells(1, Columns.Count).End(xlToLeft).Column
      

      首先对于Rows和Columns可以通过顶级的’Excel.Application’对象来引用,而xlUp和xlToLeft两个常量值,我目前采用的方案是通过文档进行查阅,首先定位到vba文档的Range.End 属性,然后再点击 Direction 参数的数据类型:https://docs.microsoft.com/zh-cn/office/vba/api/excel.xldirection

      image-20210621213313300

      于是我们翻译为:

      LastRow = Sh.Cells(excel_app.Rows.Count, 1).End(-4162).Row
      LastCol = Sh.Cells(1, excel_app.Columns.Count).End(-4159).Column
      

      专业的vba程序员都习惯用上面的方法获取数据的行数和列数,但一般情况下用我前面的UsedRange的方法就够了。

      由于数据都直接读取到python环境中,我们直接使用python的字典,继续翻译剩下的循环部分:

      D = {}
      Col = 2
      excel_app.ScreenUpdating = False
      for i in range(2, LastRow+1):
          TempStr = Sh.Cells(i, Col).Value
          if TempStr in D:
              Sht = wb.Sheets(TempStr)
              D[TempStr] += 1
              for j in range(1, LastCol+1):
                  Sht.Cells(D[TempStr], j).Value = Sh.Cells(i, j).Value
          else:
              D[TempStr] = 1
              excel_app.Sheets.Add(After=wb.Sheets(wb.Sheets.Count))
              wb.Sheets(wb.Sheets.Count).Name = TempStr
              for j in range(1, LastCol+1):
                  wb.Sheets(wb.Sheets.Count).Cells(1, j).Value = Sh.Cells(1, j).Value
      Sh.Activate()
      excel_app.ScreenUpdating = True
      

      我再按照个人的习惯重新编写一下:

      rows_dict = {}
      Col = 2
      excel_app.ScreenUpdating = False
      for i in range(2, LastRow+1):
          k = Sh.Cells(i, Col).Value
          if k not in rows_dict:
              Sht = excel_app.Sheets.Add(After=wb.Sheets(wb.Sheets.Count))
              Sht.Name = k
              Sht.Range(Sht.Cells(1, 1), Sht.Cells(1, LastCol)).Value = Sh.Range(
                  Sh.Cells(1, 1), Sh.Cells(1, LastCol)).Value
              rows_dict[k] = 1
          else:
              Sht = wb.Sheets(k)
          rows_dict[k] += 1
          Sht.Range(Sht.Cells(rows_dict[k], 1), Sht.Cells(
              rows_dict[k], LastCol)).Value = Sh.Range(Sh.Cells(i, 1), Sh.Cells(i, LastCol)).Value
      Sh.Activate()
      excel_app.ScreenUpdating = True
      

      最终完整代码:

      import win32com.client as win32  # 导入模块
      import os
      
      excel_app = win32.gencache.EnsureDispatch('Excel.Application')
      
      
      filename = "数据源.xlsx"
      filename = os.path.abspath(filename)
      
      wb = excel_app.Workbooks.Open(filename)
      Sh = wb.ActiveSheet
      LastRow = Sh.Cells(excel_app.Rows.Count, 1).End(-4162).Row
      LastCol = Sh.Cells(1, excel_app.Columns.Count).End(-4159).Column
      
      rows_dict = {}
      Col = 2
      excel_app.ScreenUpdating = False
      for i in range(2, LastRow+1):
          k = Sh.Cells(i, Col).Value
          if k not in rows_dict:
              Sht = excel_app.Sheets.Add(After=wb.Sheets(wb.Sheets.Count))
              Sht.Name = k
              Sht.Range(Sht.Cells(1, 1), Sht.Cells(1, LastCol)).Value = Sh.Range(
                  Sh.Cells(1, 1), Sh.Cells(1, LastCol)).Value
              rows_dict[k] = 1
          else:
              Sht = wb.Sheets(k)
          rows_dict[k] += 1
          Sht.Range(Sht.Cells(rows_dict[k], 1), Sht.Cells(
              rows_dict[k], LastCol)).Value = Sh.Range(Sh.Cells(i, 1), Sh.Cells(i, LastCol)).Value
      Sh.Activate()
      excel_app.ScreenUpdating = True
      wb.SaveAs(os.path.abspath("result.xlsx"))
      wb.Close()
      excel_app.Quit()
      

      经测试,原始vba代码在Excel环境中 运行耗时1秒以内,但运行以上python代码,耗时接近30秒。

      这是因为,python通过vba读取Excel数据时,存在很频繁的交互,同时也说明并不是任何vba代码都适合用python来调用。对于大部分数据读写操作,用python自带的库会便捷很多,速度也会比vba快。

    • 您还可以看一下 刘欢老师的一小时搞定简单VBA编程 Excel宏编程快速入门课程中的 文件打开、查找、关闭小节, 巩固相关知识点
    • 以下回答由chatgpt基于相关博客总结生成:

      对于问题中提到的逻辑问题的解决方案,可以根据以下步骤来确定使用VBA还是Python来实现,并如何自动化实现匹配的过程:

      步骤一:确定使用VBA还是Python来实现 1. 首先要考虑的是逻辑问题的复杂程度和要求。 - 如果逻辑问题相对简单,并且需要与Excel进行紧密交互,建议使用VBA来实现,因为VBA可以直接在Excel中运行,在处理Excel数据方面更加得心应手。 - 如果逻辑问题较复杂,需要进行数据分析、处理大量数据或需要涉及到其他非Excel操作,建议使用Python来实现,因为Python是一种功能强大的通用编程语言,可以实现更复杂的逻辑和数据处理。

      步骤二:自动化实现匹配的过程 1. 对于VBA:可以使用Excel VBA提供的函数和方法来自动化实现匹配的过程。 - 具体步骤如下: - 打开Excel,并进入VBA编辑器(按下Alt+F11)。 - 在VBA编辑器中,编写VBA代码,实现匹配的逻辑。 - 在代码中使用Excel VBA的函数和方法来获取另一个表格的最后一行的值,并进行匹配操作。 - 将代码保存,并在Excel中运行,触发自动化匹配过程。

      1. 对于Python:可以使用xlwings库来实现自动化匹配的过程。
      2. 具体步骤如下:
        • 安装xlwings库(使用pip install xlwings命令)。
        • 在Python中,使用xlwings库来打开Excel文件,并获取另一个表格的最后一行的值。
        • 编写Python代码,实现匹配的逻辑。
        • 使用xlwings库将匹配结果写入Excel中的指定位置。
        • 运行Python代码,触发自动化匹配过程。

      下面给出一个示例代码,展示如何使用Python和xlwings库来实现自动化匹配的过程:

      # 导入xlwings库
      import xlwings as xw
      
      # 打开Excel文件
      app = xw.App()  # 创建Excel应用程序
      wb = app.books.open('path_to_your_excel_file.xlsx')  # 打开指定的Excel文件
      
      # 获取另一个表格的最后一行的值
      last_row_value = wb.sheets['Sheet2'].range('A1').end('down').value
      
      # 编写匹配的逻辑
      # TODO: 在这里根据需求编写匹配的逻辑
      
      # 将匹配结果写入Excel中的指定位置
      wb.sheets['Sheet1'].range('A1').value = matched_result
      
      # 关闭Excel文件
      wb.save()  # 保存Excel文件
      wb.close()  # 关闭Excel文件
      app.quit()  # 退出Excel应用程序
      

      注意:使用上述示例代码前,请确保已安装xlwings库,并将代码中的'path_to_your_excel_file.xlsx'替换为实际的Excel文件路径,'Sheet2'和'Sheet1'替换为实际的工作表名称,以及根据实际需求编写匹配的逻辑和匹配结果的写入操作。

      以上是使用Python和VBA来实现逻辑问题和自动化匹配的解决方案。根据实际情况选择合适的方式来完成任务。

    评论

报告相同问题?

问题事件

  • 创建了问题 7月14日