2017-05-11 103 views
0

从Python开始,我找不到一种方法来实现我的最终目标,因为像eval()这样的函数在Excel VBA中不存在。根据用户输入对变量进行评估

下面是我想实现用一个简单的例子,我可以扩展:

Dim userinput as String 
userinput = inputbox("A=John, B=Kate, C=Tim", "Enter a letter that corresponds with your name: ") 
Dim A as String 
Dim B as String 
Dim C as String 

A = John 
B = Kate 
C = Tim 

Dim Phrase as Variant 
phrase = msgbox("Hello, my name is " & userinput) 

Result: 
User enters a C 
msg box pops up as "Hello, my name is Tim" 

不管我怎么努力去做,我不能有一个userinput对应一个变量,然后将其解释而在一个字符串中。如果用户的输入引用的时间太长而且复杂,用户难以自行输入,那么我的宏就没用了。

回答

4

您正在展示有限的预定义向用户提供一系列选项。

然而,你让他们毫不夸张地输入什么,没有验证,并与它一起滚动。

一个更好的替代方案将是沟InputBox方法和与实际UserForm向用户呈现,以使用户的输入约束到一个有限的,预先确定的设定的选择 - ComboBox控制想到:

some UserForm with instructions, ok, cancel buttons and a combobox control

用户窗体的代码隐藏是非常简单的 - 隐藏在单击按钮时的形式,把“X-出”为取消,暴露用户的Selection和形式是否是通过Property Get取消会员,和填充的可能值下拉列表,从挑选:

Option Explicit 
Private isCancelled As Boolean 

Public Property Get Cancelled() As Boolean 
    Cancelled = isCancelled 
End Property 

Public Property Get Selection() As String 
    Selection = ComboBox1.Value 
End Property 

Private Sub CancelButton_Click() 
    isCancelled = True 
    Hide 
End Sub 

Private Sub OkButton_Click() 
    Hide 
End Sub 

Private Sub UserForm_Activate() 
    With ComboBox1 
     .Clear 
     .AddItem "Lorem" 
     .AddItem "Ipsum" 
     '... 
    End With 
End Sub 

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer) 
    If CloseMode = vbFormControlMenu Then 
     Cancel = True 
     isCancelled = True 
     Hide 
    End If 
End Sub 

现在你可以这样做:

Public Sub Test() 
    With New UserForm1 
     .Show 
     If Not .Cancelled Then 
      MsgBox .Selection 
     End If 
    End With 
End Sub 

此处理用户抵消提示,如果你的ComboBox控制的Style属性设置为fmStyleDropDownList,那么用户绝对没有办法提供您不期望的值。您可以通过提供Property GetProperty Let成员来根据需要配置TitleInstructions标签,或者让调用代码负责提供有效值列表以填充ComboBox

这就是其中一个部分问题。下一部分是用另一个字符串值“映射”输入。这样做的最好的数据结构是Dictionary,但键入Collection可以很好的工作:

Dim values As Collection 
Set values = New Collection 
values.Add "string 1", "Lorem" 
values.Add "string 2", "Ipsum" 
'... 

With New UserForm1 
    .Show 
    If Not .Cancelled Then 
     MsgBox values(.Selection) 
    End If 
End With 

当然有很多方式来填充你所需要的数据,既为组合框值和映射的集合中的字符串;你可以像这样对它们进行硬编码,或者从工作表上的Range或者从数据库中获取它们,不管你的船是什么。

+0

糟糕,框架标题中的拼写错误。好吧。 –

+0

表单中的语言是什么?绝对是正确的方法顺便说一句。 –

+1

@ASH [* Lorem Ipsum *来自Cicero于公元前45年写成的“de Finibus Bonorum et Malorum”(极端恶魔)的第1.10.32和1.10.33节。](http:// www。 lipsum.com/);-) –

2

用户正在输入一个字母。您需要更明确地将其转换为名称的代码。有很多方法 - 如果你有一个长列表或用户输入列表,你可能需要一个更具动态性的解决方案。但是,这里是您的代码的修复:

Dim userinput as String 
userinput = inputbox("A=John, B=Kate, C=Tim", "Enter a letter that corresponds with your name: ") 
Dim A as String 
Dim B as String 
Dim C as String 
Dim nameOut as String 

select case userinput 
    case "A" 
     nameOut = "John" 
    case "B" 
     nameOut = "Kate" 
    case "C" 
     nameOut = "Tim" 
end select 

Dim Phrase as Variant 
phrase = MsgBox("Hello, my name is " & nameOut) 

注意:不要忘记用双引号括起字符串。

+0

这也是一个很好的解决方案。如果我的代码不需要绝对验证,我一定会记住! –

1

只是因为它是一种不同的方法。它在所有三个数组中找到输入字母的位置,然后在名称数组中找到相应的项目。

Sub x() 

Dim userinput As String 
Dim Phrase As String 
Dim v 

userinput = InputBox("A=John, B=Kate, C=Tim", "Enter a letter that corresponds with your name: ") 
v = Array("John", "Kate", "Tim") 

With Application 
    If IsNumeric(.Match(userinput, Array("A", "B", "C"), 0)) Then 
     Phrase = .Index(v, .Match(userinput, Array("A", "B", "C"), 0)) 
     MsgBox "Hello, my name is " & Phrase 
    Else 
     MsgBox "Wrong letter" 
    End If 
End With 

End Sub 
+0

这种方法更容易适用于在Excel中从范围中提取动态列表,如果您想要走这条路线,应该强烈考虑 – Scott

1

不从斯科特的答案带走,但对于潜在的更加动态的方法似乎class modulescallbyname有一个答案:

类模块 - class1的

Private pa As String 
Public Property Get a() As String 
a = pa 
End Property 
Public Property Let a(value As String) 
pa = value 
End Property 

测试子

Sub testing() 
Dim cls1 As Class1 
    Set cls1 = New Class1 

cls1.a = "tim" 

userinput = "a" 

Debug.Print CallByName(cls1, userinput, VbGet) 

End Sub