首页 > 解决方案 > 为什么openpyxl不断将“正常”公式更改为数组公式

问题描述

所以我有一个带有以下公式的表格

=SUMPRODUCT((IFERROR(INDEX(Tabela2[start],MATCH(((Tabela1[type]=J3) *  Tabela1[id]),Tabela2[id],0))>=$I$1;0)*1))

它只计算在某个日期之后发生并且属于某种类型的条目数

但是,当我运行openpyxl用于更新主表的脚本时,它会在前面的公式中添加大括号,从而使其返回错误的值。我可以通过正常输入而不用control+shift+center来修复它,但是每次更新它时都必须修复它有点烦人

我还制作了以下脚本,它只是打开和保存文件,它还在公式中添加了大括号。有人可以告诉我我做错了什么。

from openpyxl import load_workbook

ficheiro = 'Livro1.xlsx'
workbook = load_workbook(filename=ficheiro)
workbook.save(filename="test1 -test.xlsx")

标签: pythonexcelopenpyxl

解决方案


“......它在公式中添加了大括号。有人可以告诉我我做错了什么。”

它是 Excel 的动态数组功能,添加了 Office 365 兼容性和某些跨平台更新。它假定公式是一个数组并强制使用大括号(“{”、“}”),除非使用隐式交集运算符(“@”)。不利的一面是,旧版本的 Excel 不能识别任一运算符,并且会导致字符串变量(查找、解析、过滤、连接“&”)在 VBA 代码中崩溃。

没有办法阻止 excel 这样做,但这可能是一个有用的解决方法。

此代码在插入“@”运算符以在执行 VBA 时强制关闭动态数组函数后删除了隐式交集。这将循环遍历每个工作表并返回到原始工作表。注释掉公式列表以适应导致困难的公式的特定用途。第二个宏根据 VBA 版本通过测试它是否识别较新的数组结构来更改使用的替换函数的类型。诀窍是使用预编译标识符 (#) 来处理复古编辑器不允许的较新代码,但如果没有较新的公式将无法工作。

Sub DelOperand

Scheat = ActiveSheet.Name
Sheets(1).Select
For Count = 1 To Worksheets.Count

   'Remove forced special character'
    Run FormulaFix("Cell")
    Run FormulaFix("Column")
    Run FormulaFix("FilterXML")
    Run FormulaFix("FormulaText")
   'Run FormulaFix("Frequency")'
   'Run FormulaFix("Growth")'
    Run FormulaFix("Hyperlink")
    Run FormulaFix("If")
    Run FormulaFix("Index")
    Run FormulaFix("Indirect")
    Run FormulaFix("IsFormula")
   'Run FormulaFix("LinEst")'
   'Run FormulaFix("LogEst")'
   'Run FormulaFix("MInverse")'
   'Run FormulaFix("MMult")'
   'Run FormulaFix("Mode.MULT")'
   'Run FormulaFix("Munit")'
    Run FormulaFix("Offset")
    Run FormulaFix("Row")
    Run FormulaFix("Transpose")
   'Run FormulaFix("Trend")'

    If Count = Worksheets.Count Then Exit For
    ActiveSheet.Next.Select
Next

Sheets(Scheat).Select
Err.Clear

End Sub


Function FormulaFix(ByRef Whatzit)
'Credit: Stephen L. Rush'

Dim WhatNow
Dim ErrNum As Integer

On Error Resume Next

WhatNow = "@" & Whatzit

If Application.Evaluate("=XLOOKUP(1,{1,2,3},{3,2,1})") Then
   #If Not Err = 0 Then
    Cells.Replace What:=WhatNow, Replacement:=Whatzit, LookAt:=xlPart, _
        SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
        ReplaceFormat:=False, FormulaVersion:=xlReplaceFormula2
   #Else
    Cells.Replace What:=WhatNow, Replacement:=Whatzit, LookAt:=xlPart, _
        SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
        ReplaceFormat:=False
   #End If
End If
Next

On Error GoTo 0

End Function

推荐阅读