【问题标题】:"@" symbol appearing after inserting IF formula into excel using Openpyxl使用Openpyxl将IF公式插入Excel后出现“@”符号
【发布时间】:2021-02-02 10:56:08
【问题描述】:

我的目标是使用 Openpyxl 将此公式输入 Excel。

=CORREL(IF(A2:A7;A2:A7);B2:B7)

IF公式的原因是忽略了内部为0的单元格,CORREL函数默认不会忽略。

当将此公式插入到 excel 中时,输出实际上是:

=CORREL(IF(@A2:A7;A2:A7);B2:B7)

如果在与给定范围(此处为第 2-7 行)位于同一行的单元格中输入公式,该公式仍然有效。但是给#VALUE!当放在另一排时。手动删除“@”可以解决问题,但不可行,因为我想用它来自动分析。

我发现在某些情况下,Excel 为数组添加了“@”,并从pre-2010 versions of Excel 替换为“[#This Row]”,这解释了为什么在同一行上输入公式时有效。 当公式is not recognized. 时,openpyxl 也会将“@”符号添加到公式中 但是,这两个链接都没有解释为什么在我的示例中添加了“@”。

这是在 IF 函数中使用范围的副作用吗?这是将范围解析为 IF 函数的错误(/功能)吗?

这是我用来复制错误的代码。我的 Openpyxl 版本是 3.0.5,我使用 Microsoft 365 的 Excel。

from openpyxl import Workbook
wb = Workbook()
ws = wb.active
rows = [
    ['Size', 'Batch 1', 'Batch 2'],
    [2, 40, 30],
    [0, 40, 25],
    [0, 50, 30],
    [5, 30, 25],
    [6, 25, 35],
    [7, 20, 40],
]

for row in rows:
    ws.append(row)

formula = '=CORREL(IF(A2:A7,A2:A7),B2:B7)'
ws.cell(row=5, column=5, value=formula) # Formula in row 5 works
ws.cell(row=9, column=5, value=formula) # Formula in row 9 returns #VALUE!
formula = '=CORREL(A2:A7,B2:B7)'
ws.cell(row=6, column=5, value=formula) # CORREL function with ranges works fine
formula = '=IF(A2:A3,A2:A3)'
ws.cell(row=7, column=5, value=formula) # enters "=@IF(@A2:A3;A2:A3)"
formula = '=IF(A2,B2)'
ws.cell(row=8, column=5, value=formula) # enters "=IF(A2;B2)"

wb.save("test.xlsx")

在“test.xlsx”中,这是我的输出(单元格 E5-E9)

-0.9528
-0.9528
#VALUE!
40
#VALUE!

还有公式:

=CORREL(IF(@A2:A7;A2:A7);B2:B7)
=CORREL(A2:A7;B2:B7)
=@IF(@A2:A3;A2:A3)
=IF(A2;B2)
=CORREL(IF(@A2:A7;A2:A7);B2:B7)

【问题讨论】:

  • 这不是一个错误,它实际上是一个特性,实际上是使用动态数组的副作用。我认为可以肯定地说您获得"@" 的原因与您使用Microsoft365 有关,如here 所述。虽然由于 Python 不是我的强项,但我不知道如何通过 OpenPyxl 库解决这个问题。您需要输入数组公式。

标签: python excel-formula openpyxl


【解决方案1】:

在这里回答我自己的问题。感谢JvdV 让我走上了正确的道路。

this 答案中,我找到了解决我问题的方法。我在示例代码中保存 excel 文件之前添加了这一行:

ws.formula_attributes['E9'] = {'t': 'array', 'ref': "E9:E9"}

这实质上将单元格“E9”中的公式设置为数组公式,在 Excel 中通过大括号 ({}) 之间的公式来显示。在旧版本的 Excel 中,这是通过在输入公式时按 ctrl-shift-enter 来完成的。请注意,在公式字符串中写入这些花括号不起作用。

如果有人知道“ref”部分的工作原理,请随时在 cmets 中添加。

【讨论】:

  • 请注意,用于此的 API 在 3.1 中将发生变化,ArrayFormulae 将成为您直接分配给单元格的对象。
  • 我在不使用 formula_attributes 时添加了一个 @,并在使用 formula_attributes 时添加了大括号。有什么办法可以得到“干净”的公式?
  • 我不是 Excel 专家,但如果我理解正确,大括号只是一种将单元格解释为数组公式的可视化方式。如果我单击 Excel 中的单元格,括号会消失,之后它们不会返回。因此,也许您可​​以尝试将使用“formula_attributes”创建的每个单元格写到新工作表中,只需复制粘贴每个单元格的所有内容即可。否则,您必须更具体地说明为什么需要清洁配方。花括号是否出现在您不想要的地方?
【解决方案2】:

经过多次反复试验,我找到了一种使用 openpyxl 将简单公式输入到单元格中的方法。我通过检查从 Excel for Mac 保存的电子表格的 XML 来做到这一点。 .xlsx 文档只是一个 zip 文件。我在我的文件中找到了这些文件:

docProps/app.xml
docProps/core.xml
xl/theme/theme1.xml
xl/worksheets/sheet1.xml
xl/styles.xml
_rels/.rels
xl/workbook.xml
xl/_rels/workbook.xml.rels
[Content_Types].xml

我打开了“xl/worksheets/sheet1.xml”文件并查看了原始 XML 中的公式,该公式在我保存之前正确显示。我在相关单元格中找到了这个:

<f ca="1">_xlfn.DAYS(C2,TODAY())</f>

“_xlfn”的使用。在openpyxl docs中提到。

因此,我使用 openpyxl 使用此代码在新创建的工作簿中正确输入所需的公式:

#!/usr/bin/env python3

import openpyxl
import csv
import os

fileCSV  = os.path.expanduser('~/doc/SSL_Cert_Expiry.csv')
fileXLSX = os.path.expanduser('~/doc/SSL_Cert_Expiry.xlsx')

print(f'Using\n\tCSV {fileCSV}\n\tXLSX {fileXLSX}')

wb = openpyxl.Workbook()
ws = wb.active

with open(fileCSV, newline='') as fIn:
  sslReader = csv.reader(fIn, delimiter=',')
  for idx, row in enumerate(sslReader):
    row.append(f'=_xlfn.DAYS(C{idx + 1},TODAY())')
    ws.append(row)

wb.save(fileXLSX)

我在 Excel for Mac 中打开了这个,我的公式正确显示,而不是可怕的 !#NAME。

脚注:我原以为必须为我的公式单元格设置“ca”属性,但最终没有必要。它可以用例如来完成。

ws.formula_attributes['D2'] = {'ca': '1'}

不显示数组公式的单元格不需要“ref”属性。这可以从this page 及其邻居那里收集到。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-20
    相关资源
    最近更新 更多