如何使用VBA查找具有公式的单元格是否具有函数?

时间:2018-07-31 21:28:16

标签: excel excel-vba excel-formula

我试图确定一个单元格是否只是一个简单的引用(例如“ =A2”),因为它应该包含某种功能/计算(例如“ =sum(A2:A3)”)。基本上,我正在寻找一个已经为hasFunction或hasArithmeticOperations构建的轮子。完成研究后,找不到任何东西。

真的很难找到比个案解决方案更简单的解决方案(已将其写在一个答案中,所以请让我知道是否发现错误或其他内容),因为我想不到识别的方法...我能想到的最简单的方法是检查括号。但是,用户输入很难预测(例如“ =(A2)”)。另外,我希望它能够处理所有简单的运算符(-,+,/,*,&,^等)。必须有一种更简单的方法,然后将所有这些布局正确吗?

让我知道您对此有何看法。

3 个答案:

答案 0 :(得分:0)

我认为您正在寻找regular expression

主要问题是对于Excel,所有以“ =”开头的都是公式,并且函数类型之间没有区别。除正则表达式外,您可以解析带有两个while循环的模式,只要字符是字母,第一个就会从左向右爬行,第二个则是数字。如果您以此到达论坛的结尾,则可以成功识别参考。正如您所指出的,您必须关心外部寄生虫和类似的东西...

您介意详细说明您要实现的目标吗?如果提供了更多的上下文,也许还有更多的“即开即用”的解决方案...

答案 1 :(得分:0)

我实际上有以下解决方案。任何有兴趣的人都可以复制/粘贴以下代码,以检查是否选中了任何单元格,并查看我是否错过了任何边缘情况。

想法是这样的:即使用户选择使用括号,我们也不需要立即之前的任何内容(

类似地,我们想摆脱任何简单的算术运算符(+,-,-,*,/,^)。由于在某些输入语言(例如中文)中,两个符号可能会有所不同,因此我在此将减法和否定相加?不确定,但不想冒险...

最后,我们不需要一定范围的单元格(例如,没有“:”或“,”)。

Sub test()
    Dim rng As range
    Set rng = Selection

    MsgBox (referenceOnly(rng))

End Sub

然后我们具有测试它是否只是参考的功能

Function referenceOnly(rng As range) As Boolean

    ' Three situations tht it might has formula
    ' 1: has anything before "(" except for "="
    ' 2: has any of the simple specialsmetic operators
    ' 3: has ":" which refers to a range of cells
    referenceOnly = True

    Dim str As String
    If rng.HasFormula Then
        str = rng.Formula
    Else
        referenceOnly = False
        Exit Function
    End If

    ' start of checks
    Dim i As Integer

    ' start pos of "("
    Dim startPos As Integer

    ' check 1
    startPos = InStr(2, str, "(")
    If startPos > 0 Then
        If startPos <> 2 Then
            referenceOnly = False
            Exit Function
        End If
    End If

    ' referenceOnly 2 and 3
    Dim specials(1 To 6) As String
    specials(1) = chr(43)   '+
    specials(2) = chr(45)   '-
    specials(3) = chr(46)   '-
    specials(3) = chr(42)   '*
    specials(4) = chr(47)   '/
    specials(5) = chr(94)   '^
    specials(6) = chr(58)   ':

    For i = 2 To Len(str)
        If IsInArray(Mid(str, i, 1), specials) Then
            referenceOnly = False
            Exit Function
        End If
    Next i

End Function

Helper函数,以查看数组中是否有某些元素。从某处复制代码:)

Private Function IsInArray(valToBeFound As Variant, arr As Variant) As Boolean

'INPUT: Pass the function a value to search for and an array of values of any data type.
'OUTPUT: True if is in array, false otherwise

    Dim element As Variant
    On Error GoTo IsInArrayError: 'array is empty
        For Each element In arr
            If element = valToBeFound Then
                IsInArray = True
                Exit Function
            End If
        Next element
    Exit Function
IsInArrayError:
    On Error GoTo 0
    IsInArray = False
End Function

只是发现有人否决了这个话题。不确定哈哈是什么

答案 2 :(得分:0)

我建立了评论中建议的方法,看是否可行。结果适用于以下用例:

$A$1 | =A2 | False
$A$1 | =SUM(B2:B3) | True
$A$1 | =(A2) | False
$A$1 | =6+2 | False
$A$1 | =ORA2+ORA3 | False
$A$1 | =VLOOKUP(B1,C:C,2,0) | True
Option Explicit

Sub test()

    Dim rng As Range
    Set rng = Range("A1")

    If rng.HasFormula Then

        Debug.Print rng.Address & " | " & rng.Formula & " | " & hasOperation(Range("A1"))

    End If

End Sub

Function hasOperation(rng As Range) As Boolean

    Dim formulaText As String
    formulaText = rng.Formula

    Dim strippedFormula As String
    strippedFormula = cleanOperators(formulaText)

    If Not IsNumeric(strippedFormula) Then

        Dim testRange As Range
        On Error Resume Next
        Set testRange = Range(strippedFormula)
        On Error GoTo 0

        If testRange Is Nothing Then

            'clear out precedents from string to see if something left
            strippedFormula = clearPrecedents(strippedFormula, rng)

            If strippedFormula <> vbNullString Then
                hasOperation = True
            End If

        End If

    End If

End Function

Function cleanOperators(whichText As String) As String

    Dim holdingString As String

    holdingString = Replace(whichText, "(", "")
    holdingString = Replace(holdingString, ")", "")
    holdingString = Replace(holdingString, "+", "")
    holdingString = Replace(holdingString, "-", "")
    holdingString = Replace(holdingString, "*", "")
    holdingString = Replace(holdingString, "/", "")
    holdingString = Replace(holdingString, "^", "")
    holdingString = Replace(holdingString, ":", "")
    holdingString = Replace(holdingString, "=", "")

    cleanOperators = holdingString

End Function

Function clearPrecedents(stringToClear As String, rng As Range)

    Dim finalresult As String
    finalresult = stringToClear

    Dim prec As Range
    For Each prec In rng.Precedents
        finalresult = Replace(finalresult, prec.Address(0, 0), "")
    Next

     clearPrecedents = finalresult

End Function