将字符串评估为代码 VBA

evaluate string as code VBA

我有一个带可选参数的子程序

Public Sub FaR_Wild_Stories_Extras(ByVal rngStory As Word.Range, _
    ByVal strSearch As String, ByVal strReplace As String, _
    Optional extra1 As String = "", Optional extra2 As String = "")
  With rngStory.Find
    .ClearFormatting
    .Replacement.ClearFormatting
    .Text = strSearch
    .Replacement.Text = strReplace
    .Forward = True
    .MatchWildcards = True
    .MatchCase = True
    .IgnorePunct = True
    .IgnoreSpace = True
    .Format = False
    .Wrap = wdFindContinue
    If extra1 <> "" Then eval(extra1)
    If extra2 <> "" Then eval(extra2)
    .Execute Replace:=wdReplaceAll
  End With
End Sub

我希望能够在 extra1 中放置类似“.font.size=14”或 .MatchDiacritics = False 的内容并对其求值,以便在调用查找和替换子例程时,如果有一些特定的额外参数我想一次性包含在查找和替换中,我不必为它创建一个完整的单独子项。

有办法吗? Eval() 似乎不存在于单词 VBA 中。 Object.string 不可能,除了复制子例程或让子例程包含 10 个很少使用的可选参数之外,还有什么更聪明的方法可以构造我的代码吗?

对于更一般的情况,是否可以call像这样的sub,或者通过巧妙地传递参数来构造代码以获得相同的效果

...
call Example , true, ".prop1=5", ".prop2=6"
...

Sub Example1(x, Optional param1 As String, Optional param2 As String)
    With Application.ExampleObject
        .property1 = "foo"
        .property2 = x
        Expand (param1)
        Expand (param2)
        .excecute
    End With
End Sub

最佳选择

CallByName 允许您设置 属性 或使用以字符串命名的对象调用方法。

Sub Example(x, Optional Method1 As String ="", _
            Optional Param1 As String = "", Optional Param1Value as Variant)

    Dim MyObject as Object 
    Set MyObject = Application.ExampleObject

    'invoke a method from its name
    if method1 <> "" Then CallByName MyObject, Method1, VbMethod
    'set a property from its name and a variant representing the value to set
    if param1 <> "" Then CallByName MyObject, Param1, VbSet, Param1Value

    With MyObject
        .property1 = "foo"
        .property2 = x       
        .excecute
    End With
End Sub

(有关如何优雅地处理具有多个值的属性的信息,请参阅此线程 http://www.vbforums.com/showthread.php?405366-RESOLVED-Using-CallByName-with-variable-number-of-arguments

较早的解决方案

将 rarely-used 属性外包给外部子例程。如果您不想弄乱 Main Subroutine 的参数,与上述组合仍然有用。

Sub Example(x, Optional ExternalSub as String)
    'pull any additional rarely used properties from another sub
    Application.Run(ExternalSub)

    With Application.ExampleObject
        .property1 = "foo"
        .property2 = x       
        .excecute
    
End Sub

Sub External_MoreProperties
    Application.ExampleObject.property3 = "bar"
End Sub

聚会有点晚了,但在这种情况下我会使用 stdLambda

stdLambda 是一个外部库,开发(主要由我自己)为 VBA 带来完整的解析器、编译器和求值器。我们解析 VBA-like 代码,将其转换为字节码,然后在需要时对其进行评估,所有这些都在 VBA 运行时内完成!

这个用例的用法应该非常简单:

Public Sub FaR_Wild_Stories_Extras(ByVal rngStory As Word.Range, _
ByVal strSearch As String, ByVal strReplace As String, _
Optional ByVal extraFilters As stdICallable)

    Dim f as Find
    set f = rngStory.Find
    With f
       'Default search params:
       .ClearFormatting
       .Replacement.ClearFormatting
       .Text = strSearch
       .Replacement.Text = strReplace
       .Forward = True
       .MatchWildcards = True
       .MatchCase = True
       .IgnorePunct = True
       .IgnoreSpace = True
       .Format = False
       .Wrap = wdFindContinue
       Call extraFilters.Run(f)
       .Execute Replace:= wdReplaceAll
    End With
 End Sub
 Sub Main()
    Call FaR_Wild_Stories_Extras(Doc.Contents, "Hello","Bye", stdLambda.CreateMultiline( _ 
        ".Font.Size = 10", _ 
        ".MatchDiacritics = False" _ 
    ))
 End Sub