【问题标题】:in Excel VBA, how do I substitute local variables in a MATCH function in place of hard coded values?在 Excel VBA 中,如何用 MATCH 函数中的局部变量代替硬编码值?
【发布时间】:2018-01-01 23:29:47
【问题描述】:

我编写了一些 VBA 代码,循环遍历打开的 Excel 数据表的行,执行我在网上找到的 Evaluate(Index(Match)) 语句,在第二个 Excel 工作簿中搜索 2 个值(LastName 和 LabCat)。结果 (FirstName) 从第二个 Excel 工作簿返回并存储在局部变量中。我用这个语句成功返回了我正在寻找的值:

strFirstName = Evaluate("INDEX('[MyMatrix.xlsm]MySheet'!$C$2:$C$1000,MATCH(""Cain""&""ABO1"",'[MyMatrix.xlsm]MySheet'!$B$2:$B$1000&'[MyMatrix.xlsm]MySheet'!$H$2:$H$1000,0))")

但我无法解决的是如何用局部变量替换硬编码值,例如这个语句(我用变量 strLastName 替换字符串“cain”,并替换字符串“ABO1”使用变量 strLabCat):

strFirstName = Evaluate("INDEX('[MyMatrix.xlsm]MySheet'!$C$2:$C$1000,MATCH(""strLastName""&""strLabCat"",'[MyMatrix.xlsm]MySheet'!$B$2:$B$1000&'[MyMatrix.xlsm]MySheet'!$H$2:$H$1000,0))")

此语句将“错误 2042”返回到 strFirstName。

【问题讨论】:

    标签: excel match vba


    【解决方案1】:

    有时使用令牌替换方法比尝试进行一堆连接更容易。

    例如:

    Dim sht As Worksheet, f, strFirstName
    
    Set sht = Workbooks("MyMatrix.xlsm").Worksheets("MySheet")
    
    f = "INDEX($C$2:$C$1000,MATCH(""{LastName}""&""{LabCat}"",$B$2:$B$1000&$H$2:$H$1000,0))"
    f = Replace(f, "{LastName}", "Cain")
    f = Replace(f, "{LabCat}", "AB01")
    
    strFirstName = sht.Evaluate(f) '<< note using the Worksheet.Evaluate form here
    

    【讨论】:

    • 有趣的想法。 (让我想起了 PHP 中的 Prepared Statements。)我以前没见过在 VB 中使用它,但我能想到一些可能会派上用场的情况。
    • 同意。我在 HTML 表格中大量使用这种方法,您需要通过 VBA 在表格的特定部分添加特定文本。
    • 感谢蒂姆您的解决方案。我还没有尝试过,但我很想执行你的建议,看看它是如何工作的。我会回来报告的。
    • 蒂姆,我将您的代码 sn-p 放入我的模块中以逐步执行它,当我执行它时,我得到“错误 2042”返回给 strFirstName。我相信,在我所做的其他测试中,这基本上等同于“未找到值”,但我知道“Cain”和“ABO1”组合是有效的 - 并且可以通过长连接技术找到。我做错了什么吗?
    • 蒂姆,还有一条信息——“f”中的结果值为:“INDEX($C$2:$C$1000,MATCH("Cain"&"AB01",$B$2: $B$1000&$H$2:$H$1000,0))"
    【解决方案2】:

    您几乎拥有它,但很容易与字符串中所需的所有“双双引号”混淆,以便将“双引号”分配给字符串的值。

    用你的具体例子,如果 this 是成功的:

    strFirstName = Evaluate("INDEX('[MyMatrix.xlsm]MySheet'!$C$2:$C$1000,MATCH(""Cain""&""ABO1"",'[MyMatrix.xlsm]MySheet'!$B$2:$B$1000&'[MyMatrix.xlsm]MySheet'!$H$2:$H$1000,0))")
    

    ...但不是硬编码 CainAB01,您希望从字符串变量中获取值,如所述在您的问题中,将行更改为:

    strFirstName = Evaluate("INDEX('[MyMatrix.xlsm]MySheet'!$C$2:$C$1000,MATCH(""" & strLastName & """&""" & strLabCat & """,'[MyMatrix.xlsm]MySheet'!$B$2:$B$1000&'[MyMatrix.xlsm]MySheet'!$H$2:$H$1000,0))")
    

    稍微备份一下,考虑以下将字符串分配给变量的简单示例:

    Option Explicit
    
    Sub varTest1()
        Dim myGreeting As String
        myGreeting = "Hello, My name is Juan and I live in Mexico"
        MsgBox myGreeting
    End Sub
    

    运行此子例程,会弹出一条消息,其中包含来自 Juan 的问候。非常基本,但请注意:

    • 变量已显式声明。它可以在没有 As String 部分的情况下工作,但始终指定数据类型是一种很好的编码习惯。

    • 我使用了可选语句Option Explicit。如果使用,它必须是模块中的第一行,并且每个模块只出现一次。这样做是强制您通过在编译期间或代码执行之前生成“pickier”错误来正确声明所有变量并正确处理对象。为什么你想要更多的错误? 现在比以后[出乎意料地]更好,强烈推荐给新的编码人员和/或在进行故障排除时。

    接下来,让我们用另一个变量替换胡安的硬编码名称。

    还是很简单,像这样:

    Sub varTest2()
        Dim myGreeting As String, myName As String
        myName = "Juan"
        myGreeting = "Hello, My name is " & myName & " and I live in Mexico"
        MsgBox myGreeting
    End Sub
    

    基本上你只是concatenating a string。加号 + 用于将字符串 数字相加,但最好还是坚持使用专门用于字符串的符号 &amp;

    让我们再次添加另一个变量:

    Sub varTest3()
        Dim myGreeting As String, myName As String, myCountry As String
        myName = "Juan"
        myCountry = "Mexico"
        myGreeting = "Hello, My name is " & myName & " and I live in " & myCountry
        MsgBox myGreeting
    End Sub
    

    与#2 相同的想法;我添加示例 #2 的原因是为了证明如果变量位于字符串的末尾,则不需要额外的 " 引号。

    但是,如果我们想在句末加上句号,则该行如下所示:

        myGreeting = "Hello, My name is " & myName & " and I live in " & myCountry & "."
    

    请注意,以上所有示例都有相同的结果


    在字符串添加双引号:

    这就是" 双引号可能会让人有些困惑的地方,因为您分配给字符串的文本周围需要它们,但是我们如何将它们放在字符串中? 有几种方法。

    再次备份,我们可以在名称周围添加单引号 ',如下所示:

        myGreeting = "Hello, My name is 'Juan' and I live in Mexico."
    

    ...字符串将包含:

    您好,我叫“Juan”,住在墨西哥。

    ...但是如果我们想要 double-quotes " 围绕字符串的部分 od 出于美观原因(例如这些示例),或者出于强制性原因(例如要求)一个公式(如您的示例),我们可以做以下两件事之一:

    • 使用34ASCII字符代码添加"符号。 VBA 中的函数将是 Chr(34) 作为工作表函数 CHAR(34)
    • 或者,每次我们想要一个" 双引号时,我们使用两个双引号一起 ""(或者我称之为四引号它。)

    例如,硬编码:

    Sub varTest4()
        Dim myGreeting As String
        myGreeting = "Hello, My name is ""Juan"" and I live in Mexico."
        MsgBox myGreeting
    End Sub
    

    这将显示一个弹出消息框,上面写着:

    你好,我叫“Juan”,住在墨西哥

    或者,我们可以再次使用名称为 的变量,并且 在它周围加上双引号:

    Sub varTest5()
        Dim myGreeting As String, myName As String
        myName = """Juan"""
        myGreeting = "Hello, My name is " & myName & " and I live in Mexico"
        MsgBox myGreeting
    End Sub
    

    ...这将产生与上一个示例 (#4) 相同的结果。

    或者我们可以将双引号添加到myGreeting,而不是通过myName:\

    Sub varTest6()
        Dim myGreeting As String, myName As String
        myName = "Juan"
        myGreeting = "Hello, My name is """ & myName & """ and I live in Mexico"
        MsgBox myGreeting
    End Sub
    

    ...我们将再次得到与上面完全相同的结果。

    并且,为了演示如果我们想要在 both 名称 国家之间使用双引号会是什么样子(因此,双引号出现在非常字符串结尾):

    Sub varTest7()
        Dim myGreeting As String, myName As String, myCountry As String
        myName = "Juan"
        myCountry = "Mexico"
        myGreeting = "Hello, My name is """ & myName & """ and I live in """ & myCountry & """"
        MsgBox myGreeting
    End Sub
    

    至少有几种方法可以在字符串中添加双引号:

    • 如上使用""“四引号”,或者,
    • 使用 ASCII 字符代码(双引号为 34。)

    ...因为有时所有这些过多的引号都会让人感到困惑。

    例如,显示三个双引号,如下所示:

    """

    我需要使用:

    MsgBox """"""""

    ...这是 八个 双引号:一个用于开始字符串,一个用于结束字符串,三组两个用于显示。 (这会被称为 Octo-quote 吗?!

    我们可以显示这个:

    “娟”

    与:

    MsgBox """Juan"""
    

    ...或完全相同的结果(但在我的脑海中更清晰):

    MsgBox Chr(34) & "Juan" & Chr(34)
    

    ...因此更改示例 #7 中的行,如下:

    myGreeting = "Hello, My name is " & Chr(34) & myName & Chr(34) & _
        " and I live in " & Chr(34) &  myCountry & Chr(34)
    

    ...会产生与示例 #7 相同的结果:

    你好,我叫“Juan”,住在“墨西哥”


    最后,再考虑一下您的问题中的示例,关于字符串混乱的清晰度主题。您可以使用 下划线 _ 作为“行继续符号”将一长行代码分成多行,使其更易于阅读,无论是在 VBA 编辑器 (VBE) 中,如以及其他人在这样的网站上发布代码时阅读或复制/粘贴

    例如,我对您的代码行的“更正”是:

    strFirstName = Evaluate("INDEX('[MyMatrix.xlsm]MySheet'!$C$2:$C$1000,MATCH(""" & strLastName & """&""" & strLabCat & """,'[MyMatrix.xlsm]MySheet'!$B$2:$B$1000&'[MyMatrix.xlsm]MySheet'!$H$2:$H$1000,0))")
    

    ...一个 loooong 行(他们可以得到much loooonger!)

    在我解释引号之前,我不想让我的原始回复更加混乱,我添加额外的符号,但是一个 "cleaner" 写冗长的行是在你想继续的任何地方添加下划线在下面一行,像这样:

     strFirstName = Evaluate("INDEX('[MyMatrix.xlsm]MySheet'!$C$2:$C$1000, " & _
        "MATCH(""" & strLastName & """&""" & strLabCat & """,'[MyMatrix.xlsm]" & _
        "MySheet'!$B$2:$B$1000'[MyMatrix.xlsm]MySheet'!$H$2:$H$1000,0))")
    

    您无需在 VBE 中向右滚动即可查看代码,并注意 Stack Overflow 也无需添加水平滚动条。

    一清二楚? :-)

    祝你好运! (顺便说一下,您的问题也很贴切。欢迎!)

    更多信息:

    【讨论】:

    • 谢谢你,ashleedawg!您的解决方案正是我想要的!我以为我在附近,并尝试了多种变化,但没有得到它。再次感谢。
    • ashleedawg,当我向我的 MATCH 语句添加第三​​个条件时,我得到一个“错误 2015”返回。您的帮助将不胜感激。这是我的新声明: varFirstName2a = Evaluate("INDEX('[Master Staffing Matrix.xlsm]Master Staffing Matrix'!$C$2:$C$1500,MATCH(""" & strLastName & """&""" & strLabCat & """&""" & strStatus & """,'[Master Staffing Matrix.xlsm]Master Staffing Matrix'!$B$2:$B$1500&'[Master Staffing Matrix.xlsm]Master Staffing Matrix'! $H$2:$H$1500&'[Master Staffing Matrix.xlsm]Master Staffing Matrix'!$A$2:$A$1500,0))")。我以为我正确地添加了第三个标准。
    • 除了错误编号之外,错误的完整描述是什么?哪一行给出了错误?
    • ashleedawg,令人困惑的是代码不会像“类型不匹配”错误那样完全失败。上面指示的代码行执行没有失败,但接收变量 varFirstName2a 中的结果具有值“Error2015”而不是我期望的名字。我在任何在线文档中都找不到 MATCH 语句中有 2 个连接值的限制。而且,我认为我非常小心地将第三个 MATCH 值与适当的双引号配对。
    猜你喜欢
    • 1970-01-01
    • 2015-11-17
    • 1970-01-01
    • 2013-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-18
    • 2015-11-06
    相关资源
    最近更新 更多