超过255个字符的数组公式

5

运行VBA代码时出现错误。

运行时错误'1004': 无法设置Range类的FormulaArray属性

我猜测这是因为我的代码超过了255个字符。

如果是这样,有没有人知道我可以使用的解决方法?

下面是我的代码:

formula_string = "=-SUM("
account_counter = 1
Do Until Range("tblAccounts[[#Headers],[Accounts]]").Offset(account_counter, 0).Value = ""
    account_name = Range("tblAccounts[[#Headers],[Accounts]]").Offset(account_counter, 0).Value
    formula_string = formula_string & "IF(IFERROR(" & account_name & "[Category]=[@Categories],FALSE)*(" & account_name _
        & "[Transaction date]>=Budget!C$1)*(" & account_name & "[Transaction date]<=EOMONTH(Budget!C$1,0))," & account_name _
        & "[Outflow],0),"
    account_counter = account_counter + 1
Loop
formula_string = Left(formula_string, Len(formula_string) - 1) & ")"

    Do Until Range("tblBudget[[#Headers],[Ignore?]]").Offset(category_counter, 0).Value = ""
        If Range("tblBudget[[#Headers],[Ignore?]]").Offset(category_counter, 0).Value = "No" Then
            Do Until Range("tblBudget[[#Headers],[Ignore?]]").Offset(0, column_counter).Value = ""
                If Right(Range("tblBudget[[#Headers],[Ignore?]]").Offset(0, column_counter).Value, 8) = "Outflows" Then
                    Range("tblBudget[[#Headers],[Ignore?]]").Offset(category_counter, column_counter).Select
                    Selection.Formula = formula_string
                End If
                column_counter = column_counter + 1
            Loop
        End If
        category_counter = category_counter + 1
    Loop

如果我用".Formula"替换".FormulaArray",然后手动将其转换为数组(Ctrl+Shift+Enter),它就能正常工作,因此公式本身是没问题的。
不幸的是,我不能让它更简单,因为我可能有多达10个帐户需要在每个单元格中引用(我目前使用三个用于测试的帐户,但它会根据每个帐户的名称而改变,长度可达525个字符)。
正如我所说,Excel似乎没有问题...它是VBA存在问题。
非常感谢。
2个回答

4

我看到你的公式中有一些乘法。你可以将公式拆分成多个命名区域,然后使用另一个区域将它们组合起来。例如,假设你的公式可以分为两部分:

= formulaPart1 * formulaPart2

您可以通过以下方式定义两个命名范围:

ActiveWorkbook.Names.Add Name:="firstPart" RefersToR1C1:="formulaPart1"
ActiveWorkbook.Names.Add Name:="secondPart" RefersToR1C1:="formulaPart2"

然后您可以将最终结果设置为:

= firstPart * secondPart

编辑:您甚至可以为要求总和的每个元素定义一个命名范围。例如,这将是一个要设置的命名范围,假设您将其命名为sumElement1:

"IF(IFERROR(" & account_name & "[Category]=[@Categories],FALSE)*(" & account_name _
        & "[Transaction date]>=Budget!C$1)*(" & account_name & "[Transaction date]<=EOMONTH(Budget!C$1,0))," & account_name _
        & "[Outflow],0)"

那么公式大概是这样的:“=-SUM(sumElement1,sumElement2,...,sumElementn)”。

0

我需要插入几个非常长且复杂的公式。

我编写了一段代码,可以在英文A1表示法中插入长的公式数组函数(不带“=”开头)。

使用建议替换公式,我正在寻找最常见的命令“if()”,以尽可能多地动态替换函数。也许我可以通过分享为您节省一些工作时间。

这段代码并不是用来分享的,因此处理错误的能力很差,代码写得很糟糕。如果您需要改进它,请自行修改。代码完全用德语注释,我懒得翻译(因为我的英语不太好)。我会忘记这篇文章,可能永远不会再次查看它,所以我无法回答任何问题。

Public Sub InsertFormulaArray(formula As String, targetCell As Range)
'Die Zeile der Zellenangabe für die Platzhalter
'Existiert in der Formel eine Zeilenangabe, die diesen Wert enthält, muss dieser Wert geändert werden.
Dim uniqueLine As String
uniqueLine = 1337
'Substituiert If-Funktionen, die kürzer sind als dieser Wert
'dieser Wert muss kleiner sein als die R1C1-Notation jeder If-Funktion innerhalb der Gesamtfunktion.
Dim lenghtTolerance As Integer
lenghtTolerance = 150

'Initialisiert Array, um die Ersetzungen zu protokollieren
Dim arrLenght As Integer
arrLenght = -1
Dim replaceArr() As String

'speichert der InputString für die Prüfung am Ende
Dim InputFormula As String
InputFormula = "=" & formula


'Suche die IF Befehle
Dim currentIF As Integer
Dim replaceChar As Integer
replaceChar = Asc("A")
Dim compression As Integer

'Sprungmarke, für eine mehrdimensionale kompression
RestartReplacement:
'inputLen benötige ich für die Entscheidung, ob eine weitere kompression notwendig ist
'(vergleich vorher nachher)
Dim inputLen As Integer
inputLen = Len(formula)

'findet den Anfang der ersten If-Funktion der Formel
currentIF = InStr(1, formula, "IF(")
'Findet das Ende der aktuellen If-Funktion
While Not currentIF = 0
    'gibt die Tiefe der aktuellen If-Funktion an
    Dim depth As Integer
    depth = 0
    'gibt die position der letzten Ziffer der aktuellen If-Funktion an. (0 - nicht gefunden)
    Dim ifEnd As Integer
    ifEnd = 0

    'Setzt und initialisiert den Zähler
    '(Position im String bei der Suche nach dem Ende der Funktion)
    Dim i As Integer
    i = currentIF

    'Zu Debug-Zwecken habe ich mir die aktuelle Ziffer herausgezogen
    Dim currentChar As String
    'Schleife, bis das Ende der If-Funktion gefunden wurde - Fehler falls nicht
    While ifEnd = 0
        currentChar = Mid(formula, i, 1)
        'Ermittelt die aktuelle tiefe
        If currentChar = "(" Then
            depth = depth + 1
        End If
        If currentChar = ")" Then
            depth = depth - 1
            'Setze ifEnd, wenn genausoviele Klammern geschlossen wie geöffnet wurden
            If depth = 0 Then
                ifEnd = i
            End If
        End If
        'Zähler rauf
        i = i + 1
        'Gibt einen Fehler zurück, wenn "i" größer ist, als der String
        If i > Len(formula) And ifEnd = 0 Then
            MsgBox "Die eingegebene Formel ist keine gültige Englische Formel: " & """" & formula & """"
            End
        End If
    Wend

    'Gebe die ermittelte If-Funktion als String aus
    Dim ifFunction As String
    ifFunction = Mid(formula, currentIF, (ifEnd + 1 - (currentIF)))

    'Ersetze die IF-Formel, wenn sie kürzer ist, als lenghtTolerance
    If Len(ifFunction) < lenghtTolerance Then
        'Schreibt den String in ein Array
        arrLenght = arrLenght + 1
        ReDim Preserve replaceArr(arrLenght)
        replaceArr(arrLenght) = ifFunction

        'Substituiere die If-Funktion in die Formel
        formula = Replace(formula, ifFunction, Chr(replaceChar) & uniqueLine)
        replaceChar = replaceChar + 1

        'Wirft mich raus, wenn die Formel 26 mal substituiert wurde
        If replaceChar > Asc("Z") Then
            'Sorge dafür, dass ich beim nächsten Versuch aus dem While fliege
            currentIF = Len(formula) - 1
            'Sorge dafür, dass ich mich nicht mehr wiederhole -> compression = 0
            inputLen = Len(formula)
        End If
    End If

    'Sucht den Anfang der nächsten If-Funktion
    currentIF = InStr(currentIF + 1, formula, "IF(")
Wend
'Ermittel, wie stark die Funktion durch diesen Vorgang komprimiert wurde
compression = inputLen - Len(formula)

'Überprüft, ob noch IF-Funktionen vorhanden sind
'Wiederholt die kompression, falls die letzte kompression nicht erfolglos war
If currentIF = 0 And InStr(1, formula, "IF(") > 0 And compression > 0 Then
    GoTo RestartReplacement
End If

'Schreibt die komprimierte Formel in die gewünschte Zelle
Application.ScreenUpdating = False
targetCell.FormulaArray = ("=" & formula)

'Setzt replaceChar eins zurück, um den letzten ersetzenden Buchstaben anzugeben
replaceChar = replaceChar - 1

'Ersetzt rückwärts alle "replacements"
For i = arrLenght To 0 Step -1
    'Dim replacementStr As String
    'replacementStr = Chr(replaceChar) & uniqueLine
    targetCell.Replace What:=(Chr(replaceChar) & uniqueLine), replacement:=replaceArr(i), LookAt:=xlPart, _
    SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
    ReplaceFormat:=False
    replaceChar = replaceChar - 1
Next i
Application.ScreenUpdating = True

'Überprüfe das Ergebnis
Dim result As String
result = targetCell.FormulaArray
If result = InputFormula Then
    'Einsetzen erfolgreich!
Else
    MsgBox "Beim einsetzen einer Formel in die Zelle """ & targetCell.Address & """ ist ein Fehler aufgetreten!" & vbCrLf & "Die aktuelle Aktion wird abgebrochen!"
    End
End If
End Sub

您需要提供一行代码中从未使用过的内容(以替换if命令与单元格)。这是必要的,因为插入的公式在每个步骤中都必须对vba和excel有意义。集成的FormulaArray和Replace命令将无法处理无意义的公式,这也是我进行替换的主要原因。在这种情况下,uniqueLine为1337,但如果需要,您可以更改它。

长度容差设置为150,这意味着只有短于150个字符的公式部分才会被替换。对于R1C1表示法的公式,限制为255,即使它以A1表示法给出,所以处理后的代码比给定的公式更长,您需要一些余地。您不需要那么多余地,但对我来说有效。

祝您拥有愉快的一天,

B_Nut


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接