Excel IF 语句限制
Excel IF Statement Limited
我在 Excel 中使用 IF 语句来搜索前一列中的部分文本,以便为费用指定供应商和类别。
供应商专栏
=IF(ISNUMBER(SEARCH("tit",[@Description])),"TITAN",IF(ISNUMBER(SEARCH("Sol",[@Description])),"Soltrack",IF(ISNUMBER(SEARCH("coin",[@Description])),"Coin",IF(ISNUMBER(SEARCH("gree",[@Description])),"Green Dream Projects",IF(ISNUMBER(SEARCH("sars V",[@Description])),"SARS VAT",IF(ISNUMBER(SEARCH("sars p",[@Description])),"SARS PAYE",IF(ISNUMBER(SEARCH("acb",[@Description])),"Debit Order","")))))))
类别列
然后下一列有以下内容以获取供应商的类别
=IF(ISNUMBER(SEARCH("TITAN",[@Payee])),"Direct Operating Cost",IF(ISNUMBER(SEARCH("Soltrack",[@Payee])),"Direct Operating Cost",IF(ISNUMBER(SEARCH("Coin",[@Payee])),"Direct Operating Cost",IF(ISNUMBER(SEARCH("Green Dream Projects",[@Payee])),"Direct Operating Cost",IF(ISNUMBER(SEARCH("SARS VAT",[@Payee])),"VAT",IF(ISNUMBER(SEARCH("SARS PAYE",[@Payee])),"PAYE",IF(ISNUMBER(SEARCH("Debit Order",[@Payee])),"Debit Order","")))))))
效果很好,但似乎我已经达到了可以在一个公式中使用的 IF 语句的限制 (7)?
我创建了以下函数来搜索文本“tit”,如果匹配则更新收款人列。
'excel if range of cells contains specific text vba
Sub MacroToCheckIfRangeOfCellsContainsSpecificText_vba()
Set Rng = Range("B2:B572") ' You can change this
specificText = "*tit*" ' You can change this
For Each Cell In Rng.Cells
If UCase(Cell.Value) Like "*" & UCase(specificText) & "*" Then
Cell.Offset(0, 1) = "Titan"
Else
Cell.Offset(0, 1) = ""
End If
Next
End Sub
我是否需要为每个关键字创建一个新的 specificText = "*tit*"
并为每个“For Each”函数创建一个完整的部分?
字典解决方案
第一个想法是使用字典 Replacements
并在其中添加所有 serach/replace 对。这有一个很大的缺点。不混合逻辑(代码)和数据是违反良好做法的。好的做法是不将数据放入代码中,而是放入工作表中(参见下一个解决方案)。
Option Explicit
Public Sub MacroToCheckIfRangeOfCellsContainsSpecificText_vba()
Dim RngToCheck As Range
Set RngToCheck = ThisWorkbook.Worksheets("Sheet1").Range("B2:B572") ' specify in which workbook and worksheet
Dim Replacements As Object
Set Replacements = CreateObject("Scripting.Dictionary")
With Replacements
.Add "tit", "Titan"
.Add "sol", "Soltrack"
'add more here
End With
Dim InputValues() As Variant
InputValues = RngToCheck.Value 'read input values into array
Dim OutputValues() As Variant 'create an output array (same size as RngToCheck)
ReDim OutputValues(1 To RngToCheck.Rows.Count, 1 To 1)
Dim iRow As Long
For iRow = 1 To UBound(OutputValues, 1)
Dim Key As Variant
For Each Key In Replacements.Keys
If UCase(InputValues(iRow, 1)) Like "*" & UCase(Key) & "*" Then
OutputValues(iRow, 1) = Replacements(Key)
Exit For 'we don't need to test for the others if we found a key
End If
Next Key
Next iRow
'write output values from array next to input values in the cells
RngToCheck.Offset(ColumnOffset:=1).Value = OutputValues
End Sub
工作表解决方案
更好的解决方案是创建一个新的工作表 Replacements
,如下所示:
这可以由任何人轻松编辑,如果您想删除或添加对,您以后不需要 fiddle 使用代码。
Public Sub ImprovedCheckUsingWorksheet()
Dim RngToCheck As Range
Set RngToCheck = ThisWorkbook.Worksheets("Sheet1").Range("B2:B572") ' specify in which workbook and worksheet
Dim Replacements() As Variant 'read replacements from worksheet
Replacements = ThisWorkbook.Worksheets("Replacements").Range("A2", ThisWorkbook.Worksheets("Replacements").Cells(Rows.Count, "B").End(xlUp)).Value 'read input values into array
Dim InputValues() As Variant
InputValues = RngToCheck.Value 'read input values into array
Dim OutputValues() As Variant 'create an output array (same size as RngToCheck)
ReDim OutputValues(1 To RngToCheck.Rows.Count, 1 To 1)
Dim iRow As Long
For iRow = 1 To UBound(OutputValues, 1)
Dim rRow As Long
For rRow = 1 To UBound(Replacements, 1)
If UCase(InputValues(iRow, 1)) Like "*" & UCase(Replacements(rRow, 1)) & "*" Then
OutputValues(iRow, 1) = Replacements(rRow, 2)
Exit For 'we don't need to test for the others if we found a key
End If
Next rRow
Next iRow
'write output values from array next to input values in the cells
RngToCheck.Offset(ColumnOffset:=1).Value = OutputValues
End Sub
对于替换工作表中的 3ʳᵈ 列,您需要将以下行调整为直到列 "C"
:
Replacements = ThisWorkbook.Worksheets("Replacements").Range("A2", ThisWorkbook.Worksheets("Replacements").Cells(Rows.Count, "C").End(xlUp)).Value 'read input values into array
并且输出值也需要另一列(第二个参数需要 1 To 2
):
ReDim OutputValues(1 To RngToCheck.Rows.Count, 1 To UBound(Replacements, 2) - 1) 'this works for any amount of columns as it reads the column count from the `Replacements`
需要写入数据
OutputValues(iRow, 1) = Replacements(rRow, 2) 'first output column
OutputValues(iRow, 2) = Replacements(rRow, 3) 'second output column
写入输出值也需要调整:
RngToCheck.Offset(ColumnOffset:=1).Resize(ColumnSize:=UBound(OutputValues, 2)).Value = OutputValues 'this works for any amount of columns as it reads the column count from `OutputValues`
公式解
但是,如果您的数据位于上述工作表 Replacements
中,并且您不依赖于部分匹配。那么您就不需要 VBA 并且可以轻松地使用公式来查找它:
=IFERROR(INDEX(Replacements!B:B,MATCH(B:B,Replacements!A:A,0)),"")
我在 Excel 中使用 IF 语句来搜索前一列中的部分文本,以便为费用指定供应商和类别。
供应商专栏
=IF(ISNUMBER(SEARCH("tit",[@Description])),"TITAN",IF(ISNUMBER(SEARCH("Sol",[@Description])),"Soltrack",IF(ISNUMBER(SEARCH("coin",[@Description])),"Coin",IF(ISNUMBER(SEARCH("gree",[@Description])),"Green Dream Projects",IF(ISNUMBER(SEARCH("sars V",[@Description])),"SARS VAT",IF(ISNUMBER(SEARCH("sars p",[@Description])),"SARS PAYE",IF(ISNUMBER(SEARCH("acb",[@Description])),"Debit Order","")))))))
类别列
然后下一列有以下内容以获取供应商的类别
=IF(ISNUMBER(SEARCH("TITAN",[@Payee])),"Direct Operating Cost",IF(ISNUMBER(SEARCH("Soltrack",[@Payee])),"Direct Operating Cost",IF(ISNUMBER(SEARCH("Coin",[@Payee])),"Direct Operating Cost",IF(ISNUMBER(SEARCH("Green Dream Projects",[@Payee])),"Direct Operating Cost",IF(ISNUMBER(SEARCH("SARS VAT",[@Payee])),"VAT",IF(ISNUMBER(SEARCH("SARS PAYE",[@Payee])),"PAYE",IF(ISNUMBER(SEARCH("Debit Order",[@Payee])),"Debit Order","")))))))
效果很好,但似乎我已经达到了可以在一个公式中使用的 IF 语句的限制 (7)?
我创建了以下函数来搜索文本“tit”,如果匹配则更新收款人列。
'excel if range of cells contains specific text vba
Sub MacroToCheckIfRangeOfCellsContainsSpecificText_vba()
Set Rng = Range("B2:B572") ' You can change this
specificText = "*tit*" ' You can change this
For Each Cell In Rng.Cells
If UCase(Cell.Value) Like "*" & UCase(specificText) & "*" Then
Cell.Offset(0, 1) = "Titan"
Else
Cell.Offset(0, 1) = ""
End If
Next
End Sub
我是否需要为每个关键字创建一个新的 specificText = "*tit*"
并为每个“For Each”函数创建一个完整的部分?
字典解决方案
第一个想法是使用字典 Replacements
并在其中添加所有 serach/replace 对。这有一个很大的缺点。不混合逻辑(代码)和数据是违反良好做法的。好的做法是不将数据放入代码中,而是放入工作表中(参见下一个解决方案)。
Option Explicit
Public Sub MacroToCheckIfRangeOfCellsContainsSpecificText_vba()
Dim RngToCheck As Range
Set RngToCheck = ThisWorkbook.Worksheets("Sheet1").Range("B2:B572") ' specify in which workbook and worksheet
Dim Replacements As Object
Set Replacements = CreateObject("Scripting.Dictionary")
With Replacements
.Add "tit", "Titan"
.Add "sol", "Soltrack"
'add more here
End With
Dim InputValues() As Variant
InputValues = RngToCheck.Value 'read input values into array
Dim OutputValues() As Variant 'create an output array (same size as RngToCheck)
ReDim OutputValues(1 To RngToCheck.Rows.Count, 1 To 1)
Dim iRow As Long
For iRow = 1 To UBound(OutputValues, 1)
Dim Key As Variant
For Each Key In Replacements.Keys
If UCase(InputValues(iRow, 1)) Like "*" & UCase(Key) & "*" Then
OutputValues(iRow, 1) = Replacements(Key)
Exit For 'we don't need to test for the others if we found a key
End If
Next Key
Next iRow
'write output values from array next to input values in the cells
RngToCheck.Offset(ColumnOffset:=1).Value = OutputValues
End Sub
工作表解决方案
更好的解决方案是创建一个新的工作表 Replacements
,如下所示:
这可以由任何人轻松编辑,如果您想删除或添加对,您以后不需要 fiddle 使用代码。
Public Sub ImprovedCheckUsingWorksheet()
Dim RngToCheck As Range
Set RngToCheck = ThisWorkbook.Worksheets("Sheet1").Range("B2:B572") ' specify in which workbook and worksheet
Dim Replacements() As Variant 'read replacements from worksheet
Replacements = ThisWorkbook.Worksheets("Replacements").Range("A2", ThisWorkbook.Worksheets("Replacements").Cells(Rows.Count, "B").End(xlUp)).Value 'read input values into array
Dim InputValues() As Variant
InputValues = RngToCheck.Value 'read input values into array
Dim OutputValues() As Variant 'create an output array (same size as RngToCheck)
ReDim OutputValues(1 To RngToCheck.Rows.Count, 1 To 1)
Dim iRow As Long
For iRow = 1 To UBound(OutputValues, 1)
Dim rRow As Long
For rRow = 1 To UBound(Replacements, 1)
If UCase(InputValues(iRow, 1)) Like "*" & UCase(Replacements(rRow, 1)) & "*" Then
OutputValues(iRow, 1) = Replacements(rRow, 2)
Exit For 'we don't need to test for the others if we found a key
End If
Next rRow
Next iRow
'write output values from array next to input values in the cells
RngToCheck.Offset(ColumnOffset:=1).Value = OutputValues
End Sub
对于替换工作表中的 3ʳᵈ 列,您需要将以下行调整为直到列 "C"
:
Replacements = ThisWorkbook.Worksheets("Replacements").Range("A2", ThisWorkbook.Worksheets("Replacements").Cells(Rows.Count, "C").End(xlUp)).Value 'read input values into array
并且输出值也需要另一列(第二个参数需要 1 To 2
):
ReDim OutputValues(1 To RngToCheck.Rows.Count, 1 To UBound(Replacements, 2) - 1) 'this works for any amount of columns as it reads the column count from the `Replacements`
需要写入数据
OutputValues(iRow, 1) = Replacements(rRow, 2) 'first output column
OutputValues(iRow, 2) = Replacements(rRow, 3) 'second output column
写入输出值也需要调整:
RngToCheck.Offset(ColumnOffset:=1).Resize(ColumnSize:=UBound(OutputValues, 2)).Value = OutputValues 'this works for any amount of columns as it reads the column count from `OutputValues`
公式解
但是,如果您的数据位于上述工作表 Replacements
中,并且您不依赖于部分匹配。那么您就不需要 VBA 并且可以轻松地使用公式来查找它:
=IFERROR(INDEX(Replacements!B:B,MATCH(B:B,Replacements!A:A,0)),"")