宏根据标头值连接两列

时间:2016-01-26 17:12:25

标签: excel vba excel-vba concatenation

我在包含许多列的Excel电子表格中有两列。我想合并这两列,但它们在工作表中的位置可能会有所不同。这意味着我需要利用第一行列标题来确定要连接哪两列。我希望将结果添加为工作表中的下一列。

例如,如果“Brand”,“Line”和“Product”在第1行作为列标题,则宏应在“Brand”中搜索该值并将其与“Model”中的值连接并放入导致工作表中的插入列(在这种情况下为D,但可能会根据列数更改)。我不能使用列或单元格引用,因为Brand和Model列的位置可能会更改,以及列数:

A | C | ç|
品牌|线|型号|
宾得|摄像机| K-30 |
本田|汽车|雅阁|
苹果|计算机| MacBook Air |

这是我尝试过的:

Sub Insrt()
    Dim Model As Range
    Dim Brand As Range
    Dim LastRow As Long
    Set Brand = Rows(1).Find(what:="Brand", LookIn:=xlValues, lookat:=xlWhole)
    Set Model = Rows(1).Find(what:="Model", LookIn:=xlValues, lookat:=xlWhole)
    If Found Is Nothing Then Exit Sub
    LastRow = Cells(Rows.Count, Brand.Column).End(xlUp).Row
    Model.Offset(, 1).EntireColumn.Insert
    Cells(1, Model.Column + 1).Value = "Concatenated_Value"
    Range(Cells(2, Model.Column + 1), Cells(LastRow, Model.Column + 1)).Formula = "=A2&C2"
End Sub

这种方法的问题在于我的公式是专门连接A列和A列。 C.然而,品牌和模型可能不会每次都出现在这些特定的列中 - 将来,它们可能会转移位置。我如何改进这一点,以便我没有明确地调用列A和C,而是使用列标题?

3 个答案:

答案 0 :(得分:2)

我喜欢使用索引/匹配:

=F2 & " " &INDEX(A:C,MATCH(F2,A:A,0),MATCH("Model",1:1,0))

enter image description here

无论在哪里"型号"最终它会找到正确的列。

对于VBA。将公式更改为

"=" & Cells(2,brand.column).address(0,0) & "&" & Cells(2,model.column).address(0,0)

答案 1 :(得分:2)

尝试:

=HLOOKUP("Brand",A:C,ROW(),0) & " " & HLOOKUP("Model",A:C,ROW(),0)

答案 2 :(得分:0)

我在编辑的原始问题中修改了代码。

1-选项明确总是一个好主意。

2-考虑了2列标题搜索,更多DRY,特别是如果需要添加更多列以供查找。

2.a-此外,如果找不到,那么'测试没有工作,至少不在我的盒子上。即使它有效,它也没有给出任何信息。无声失败可能没问题,但往往不行。现在任何未找到的标题都会给出一条消息。

2.b-在Find()中添加了MatchCase:= True可能不是想要的改变,但确实显示为什么DRY代码(不要重复自己)有所帮助。如果您不喜欢这种变化很酷,您只需编辑一个地方即可将其更改回来,而不是为每个标题编辑一个地方编辑一个地方,而不是2,3或4个地方。

3-一个答案有片段' Cells(2,brand.column)。地址(0,0)'但Range对象上的Address()方法以大写A开头,但Excel ADDRESS函数全部大写。 ADDRESS函数文档说ADDRESS(0,0)是一个OK调用但是Range对象docs上的Address(0,0)方法说两个0值是Address()看到的变体为True或不是。

我修改为.Address(RowAbsolute:= False)所以不必将0理解为False,我们也希望ColumnAbsolute为True,这是默认值。我们想要一个绝对的,一个相对的,所以当编码地址(0,0)

时它们都是相同的

4-变量Formula9仅用于简化调试。它可以在调试后编辑出来。另一方面,重复如何分配' Cells(2,Brand.Column)。地址(RowAbsolute:= False)'

所以也许是一个函数来分解' Cells(x,y).Address(RowAbsolute:= False)'会更干。

要留下多少个临时变量,要使代码更多DRY的分解是判断调用。

Option Explicit
Function FindOrMsg(toFind As String) As Range
    Dim Rtn As Range
    Set Rtn = Rows(1).Find(what:=toFind, LookIn:=xlValues, _
                           lookat:=xlWhole, MatchCase:=True)
    Set FindOrMsg = Rtn
    If Rtn Is Nothing Then MsgBox "Header '" & toFind & "' not found"
End Function

Sub Macro1()
    Dim Model As Range
    Dim Brand As Range
    Dim LastRow As Long
    Set Brand = FindOrMsg("Brand")
    Set Model = FindOrMsg("Model")
    If (Brand Is Nothing) Or (Model Is Nothing) Then Exit Sub
    LastRow = Cells(Rows.Count, Brand.Column).End(xlUp).Row
    Model.Offset(, 1).EntireColumn.Insert
    Cells(1, Model.Column + 1).Value = "Concatenated_Value"

    Dim Formula9
    Formula9 = "=" & Cells(2, Brand.Column).Address(RowAbsolute:=False) & "&" _
                   & Cells(2, Model.Column).Address(RowAbsolute:=False) & ""
    Range(Cells(2, Model.Column + 1), Cells(LastRow, Model.Column + 1)).Formula = Formula9
End Sub