【发布时间】:2023-03-20 10:04:01
【问题描述】:
在我搜索要在 VLOOKUP 公式中读取的代码并将其转换为 INDEX/MATCH 的所有搜索结果都为空之后,我自己写了一些。
但是,代码(如下)缺乏我想要的一些灵活性,但我似乎无法弄清楚如何使其工作。具体来说,我想测试 VLOOKUP 公式中的每个范围标准是否是绝对参考,即前面有 $,并将其传递给结果的 INDEX/MATCH 公式。例如,公式=VLOOKUP(A2,$A$1:B$11,2,FALSE) 应转换为=INDEX(B$1:B$11,MATCH(A2,$A1:$A11,0))。
注意:这个 sub 依赖于两个函数(ColumnLetterToNumber 和 ColumnNumberToLetter)。正如它们的名字所暗示的那样,它们采用列字母或数字并将它们相互转换。这两个功能都很短、简单,而且工作起来没有问题。但是,如果有人认为对其中一个或两个的代码有帮助,我很乐意提供。
此外,任何关于提高代码可读性和/或执行效率的想法也将不胜感激。
Option Explicit
Public Sub ConvertToIndex()
Dim booLookupType As Boolean
Dim booLeftOfColon As Boolean
Dim booHasRowRef As Boolean
Dim lngStartCol As Long
Dim lngRefCol As Long
Dim lngStart As Long
Dim lngEnd As Long
Dim lngMatchType As Long
Dim lngInt As Long
Dim lngRowRef As Long
Dim strRefCol As String
Dim strOldFormula As String
Dim strNewFormula As String
Dim strLookupCell As String
Dim strValueCol As String
Dim strMatchCol As String
Dim strStartRow As String
Dim strEndRow As String
Dim strCheck As String
Dim strLookupRange As String
Dim strTabRef As String
Dim strSheetRef As String
Dim rngToMod As Range
Dim rngModCell As Range
Set rngToMod = Selection
For Each rngModCell In rngToMod
strOldFormula = rngModCell.Formula
lngStart = InStrRev(strOldFormula, "VLOOKUP(")
If lngStart > 0 Then
lngStart = InStr(lngStart, strOldFormula, "(") + 1
lngEnd = InStr(lngStart, strOldFormula, ",")
strLookupCell = Mid(strOldFormula, lngStart, lngEnd - lngStart)
lngStart = lngEnd + 1
lngEnd = InStr(lngStart, strOldFormula, ",")
strLookupRange = Mid(strOldFormula, lngStart, lngEnd - lngStart)
lngStart = lngEnd + 1
lngEnd = InStr(lngStart, strOldFormula, ",")
lngRefCol = CInt(Mid(strOldFormula, lngStart, lngEnd - lngStart))
lngStart = lngEnd + 1
lngEnd = InStr(lngStart, strOldFormula, ")")
booLookupType = (Mid(strOldFormula, lngStart, lngEnd - lngStart) = "TRUE")
If booLookupType Then
lngMatchType = 1
Else
lngMatchType = 0
End If
booLeftOfColon = True
lngEnd = InStr(1, strLookupRange, "]")
If lngEnd > 0 Then
strSheetRef = Left(strLookupRange, lngEnd)
strLookupRange = Right(strLookupRange, Len(strLookupRange) - lngEnd)
Else
strSheetRef = ""
End If
lngEnd = InStr(1, strLookupRange, "!")
If lngEnd > 0 Then
strTabRef = Left(strLookupRange, lngEnd)
strLookupRange = Right(strLookupRange, Len(strLookupRange) - lngEnd)
Else
strTabRef = ""
End If
For lngInt = 1 To Len(strLookupRange)
strCheck = Mid(strLookupRange, lngInt, 1)
Select Case True
Case strCheck = ":"
booLeftOfColon = False
Case booLeftOfColon
If IsNumeric(strCheck) Then
strStartRow = strStartRow & strCheck
Else
strMatchCol = strMatchCol & strCheck
End If
Case Else
If IsNumeric(strCheck) Then strEndRow = strEndRow & strCheck
End Select
Next lngInt
strMatchCol = Replace(strMatchCol, "$", "")
lngStartCol = ColumnLetterToNumber(strMatchCol)
strValueCol = ColumnNumberToLetter(lngStartCol + lngRefCol - 1)
If Len(strStartRow) > 0 Then strStartRow = "$" & strStartRow
If Len(strEndRow) > 0 Then strEndRow = "$" & strEndRow
strValueCol = strSheetRef & strTabRef & strValueCol & strStartRow & ":" & strValueCol & strEndRow
strMatchCol = strSheetRef & strTabRef & strMatchCol & strStartRow & ":" & strMatchCol & strEndRow
strNewFormula = "=INDEX(" & strValueCol & ",MATCH(" & "$" & strLookupCell & "," & strMatchCol & "," & lngMatchType & "))"
rngModCell.Formula = strNewFormula
End If
Next rngModCell
End Sub
目前,我不寻求帮助以使其能够处理 VLOOKUP/HLOOKUP 或 VLOOKUP/MATCH 组合公式的下一步。
【问题讨论】:
-
首先,按逻辑:
=VLOOKUP(A2,$A$1:B$11,2,FALSE)应该转换为=INDEX($B$1:B$11,MATCH(A2,$A$1:A$11,0))!对于开始和结束的行以及开始的列,范围是绝对的,这也应该是您的结果的情况。虽然这对您的情况没有那么大的问题,但您将使用更复杂的公式遇到巨大的问题。但是,如果不阅读您的子内容,我会尝试自己编写一个(因为这看起来很棘手,我和我都喜欢这样的任务);) -
我不太明白。首先,您在代码中消除了所有
$,现在您想继续使用它们吗?那么,为什么你首先要消除它们呢?顺便说一句,您似乎正在通过现有的VLookUp公式解析上述代码,并尝试将其分解为各个部分。然而,这种方法似乎并没有克服像=VLOOKUP(IF(G4=0,1,2),A1:B10,1,1)这样的复合公式的可能性。 -
@DirkReichel 我给出的转换示例的关键是在VLOOKUP中,B前面没有$(允许扩大范围),虽然显然VLOOKUP不利于拖动公式,这就是我的一些同事设置他们的 VLOOKUPS 以准备扩大范围的方式。
-
@Ralph 我删除了 $ 因为它是最方便的解决方案,可以在某些情况下不复制它们或将它们添加到我不想要它们的地方。我目前正在避免使用复合公式的可能性,因为我写这个只是为了处理我的同事编写的公式,他们都没有证明使用像你的例子这样的复杂性。
-
@PaaquaGrant 你是对的......虽然它没有意义,因为它仍然适用于第 2 列。要获取该列,您还需要获取参数而不仅仅是范围。也就是说,您需要覆盖该列来选择值,而不是直接作为范围,而是使用
INDEX([full input range],[the match formula],[the part which points at the column]),因此对于您的示例,它应该看起来像=INDEX($A$1:B$11,MATCH(A2,$A$1:$A$11,0),2)...在这种情况下,它看起来也更容易一些,因为不需要多次分割整个范围。