使用VBA评估字符串布尔表达式

时间:2014-08-04 19:33:53

标签: vba boolean eval

我需要在VBA中评估字符串布尔表达式,例如:" 1和(0或0或1)" (这应评估为" 1"。)

我正在寻找像Python" eval"功能。使用VBA有一种简单的方法吗?谢谢!

3 个答案:

答案 0 :(得分:0)

您可以调用.Eval() ActiveX的ScriptControl方法以避免任何字符串预处理:

Sub TestEvaluateExpression()
    Dim varResult As Variant
    Dim strEvalContent As String
    strEvalContent = "1 and (0 or 0 or 1)"
    varResult = Eval(strEvalContent)
    MsgBox varResult
End Sub

Function Eval(strEvalContent As String) As Variant
    With CreateObject("ScriptControl")
        .Language = "VBScript"
        Eval = .Eval(strEvalContent)
    End With
End Function

答案 1 :(得分:0)

除了omegastripes的回答,请注意脚本控制是32位。随着64位成为常态,我不愿意使用任何只有32位的解决方案。

对于64位脚本控制选项,请参阅:

Microsoft Script Control 64 bit?

但这仍然是一个尴尬的解决方案,我不会推荐它。它要求用户安装新的DLL,并要求VBA程序员调用JavaScript,即使JS确实具有相对安全的“eval”功能。从安全角度来看,这可能不是最佳方法,并且由于Microsoft没有64位版本,因此不推荐使用32位版本,或者至少弃用。

以下是我更喜欢的其他一些方法:

  1. 获得更多爱好者并使用RegEx:
  2. How to use Regular Expressions (Regex) in Microsoft Excel both in-cell and loops

    但是,RegEx在字符串方面的效果要比使用数字方式好得多。 (如果你想将它与数字一起使用,那么你可以尝试类似于我在下面演示的内容,即单独进行数字评估。)

    1. 使用处理布尔表达式的VBA脚本,例如来自Ashley Harris的搜索字符串的this one。哈里斯的功能适用于文本或普通布尔(表达式为True和False)。如果您需要评估数字,那么您将不得不尝试其他方法,或者添加图层。
    2. 添加图层的最简单建议是将每个短数字表达式括在括号中并在传递之前对其进行评估。下面,我展示了一个简单的例子来评估这些括号内的表达式(在本例中为“[[”和“]]”),因此用户可以将自定义表达式写为“[[(20>(15+) 1))]]和([[7> 2]]或[[5 = 4]])“。

      因此,=BacketEval("[[(20 > (15+1) )]] AND ([[7>2]] OR [[5=4]])")只会将其简化为“(True)AND(True或False)”,您可以将其插入到布尔解析器中。类似的方法适用于其他解析器。

      Function BracketEval(BoolExp As String, Optional OpenBracket = "[[", Optional CloseBracket = "]]") As String
      
          Dim BoolStartPos As Integer
          Dim BoolEndPos As Integer
          Dim BoolToEval As String
          Dim BoolEvaled As String
      
          BoolStartPos = InStr(BoolExp, OpenBracket)
          BracketEval = BoolExp
      
          Do While BoolStartPos <> 0
      
              BoolEndPos = InStr(BoolStartPos + 1, BracketEval, CloseBracket)
              BoolToEval = Mid(BracketEval, BoolStartPos + Len(OpenBracket), BoolEndPos - BoolStartPos - Len(CloseBracket))
              BoolEvaled = CStr(Application.Evaluate(BoolToEval))
      
              BracketEval = Left(BracketEval, BoolStartPos - 1) _
               & BoolEvaled _
               & Right(BracketEval, Len(BracketEval) - BoolEndPos - Len(CloseBracket) + 1)
      
              BoolStartPos = InStr(BoolStartPos + Len(OpenBracket) - 1, BracketEval, OpenBracket)
      
          Loop
      
      End Function
      

      一个完整的解析器,甚至是一个可以为VBA风格的表达式添加括号的解析器,超出了我想要的范围,已经是一个冗长的(虽然不是很受欢迎!)的答案,这太复杂了,虽然我已经涉足过那些。

      这里提出了一些不寻常的解决方案:

      Evaluate Excel VBA boolean condition (not a formula)

      其中最好的是:

      1. 如果安装了Access,则通过Access对象评估VBA中的表达式。如果您只需要评估几个表达式并知道用户将具有Access,那么这是一个非常简单的解决方案。
      2. 你也可以:

        1. Create an Internet Explorer browser object并通过JavaScript评估布尔值。同样,也许不是超级优雅,但这里的优点是大多数Windows计算机都安装了IE。 (如果碰巧遇到自动化问题,请尝试创建InternetExplorerMedium对象而不是普通的旧InternetExplorer。)
        2. 对于某些人来说,下面可能是最快和最优雅的答案,特别是如果你想使用更快的引擎来淘汰其中一些:

          1. 您可以从另一个脚本引擎调用外部脚本,例如Python,AutoHotkey,R,PHP或其他类似的东西。 PowerShell可能有意义,除了调整其安全设置可能会对某些用户造成麻烦。最快(计算)可能是调用外部脚本,然后从该脚本中直接访问Excel电子表格对象(以获取表达式),执行所有必要的评估,然后关闭脚本。
          2. 从那里开始,可用的选择在质量上有所下降。

            1. 如上所述,如果您愿意降低Excel的安全设置,则可以通过暴力VBA代码注入来评估表达式。这几乎肯定是一个可怕的想法,但如果你只使用一个电子表格,永远不要使用互联网,不要与任何人分享代码,和/或是一个天生的叛徒,不像法官莱因霍尔德拒绝这样做“靠书”,那么它可能是最快的。如果你使用这种方法(你做坏妈妈),我甚至可能准备在你的防病毒软件中禁用启发式扫描! (如果这不能说服你这是一个坏主意,我想没有什么会。)
            2. 如果您只有几个要评估的表达式,并且它们是静态的,那么您可以将它们转换为标准的Excel电子表格语言。但是如果你想说接受用户的表达式,那么要求他们使用Excel在其常规函数语言中使用的笨拙的括号AND,OR和NOT是非常笨拙的。 VBA自己对表达式的评估看起来很正常,但是VBA不能轻易地将代码作为字符串传递给自己(这通常是一件好事)。

答案 2 :(得分:0)

请参阅 stdVBA 项目的 stdLambda

Debug.Print stdLambda.Create("1 and (0 or 0 or 1)").Run  '=> True

通常您会传入有效参数而不是实际创建字符串,例如

set lambda = stdLambda.Create("$1.a and ($1.b < 10 or $1.c < 10 or $1.d < 100)")
Debug.Print lambda.Run(myObj)