我一直在研究下面的问题一段时间了,我得到了一个非常基本的版本,无需处理错误。我的目标是从个人宏工作簿中运行此宏。
我从各种来源导入管道分隔的文本文件,并且标题中没有任何格式匹配(某些提供商决定使用整个布局)。有了这个问题,我创建了一个名为Reference(aka Map)的Excel工作簿,其中包含传入文件布局和标准化/更正列的名称格式。
对我来说好消息是,文件ID将始终位于A列。我每个月需要处理大约65个文件,因此我需要最小化所有可能的步骤,因此需要关闭参考工作簿。 / p>
有了这个,我在网上浏览并整理了大部分解决方案,根据A3中的ID提取新的标题。然而仍然存在两难困境,有时A3上的ID不会出现在参考工作簿上 - 我需要让vlookup向下移动到下一行,直到结果不等于#N / A或0或空白。
此时我得到了“Do Loop Until”以找到第一场比赛的正确行 - 与之后的任何代码完美配合。
只要vlookup找到具有现有ID的行,然后运行下面的代码段以填充其余标题。下一步的唯一副作用是,由于某种原因rID偏移+1行,如果最后一行不包含匹配的ID,则撤消'Do Loop until'。
'> Populate remining headers
For Each cell In rng1
cell.Value = ("=VLOOKUP(" & cID & rID & "," & map & "," & i & ",FALSE)")
i = i + 1
Next
这是我到目前为止所做的:
Sub DAc_lookup_headers()
Dim wb1 As Workbook 'Current text/file
Dim map As String 'reference Map
Dim cID As String 'wb1 look up column A
Dim rID As String 'wb1 starting row number
Dim rng1 As Range 'wb1 Collection header range
Dim i As Long 'Index number per cell in range
Set wb1 = ActiveWorkbook
Set rng1 = wb1.ActiveSheet.[A1:G1]
map = ("'C:\Users\x165422\Desktop\New folder\[Reference.xlsx]Ref'!$A$1:$I$13")
rID = 3 'Row where ID is - will increment + 1 if not found
cID = "A" 'Column where ID is
i = 3 'Starting vlookup Index number - to increment per cell in range
'>Look for ID until value is found
Do
wb1.ActiveSheet.[a1].Value = ("=VLOOKUP(" & cID & rID & "," & map & "," & i & ",FALSE)")
rID = rID + 1
Loop Until wb1.ActiveSheet.[a1].Text <> "#N/A" Or "0"
'> Populate remining headers
For Each cell In rng1
cell.Value = ("=VLOOKUP(" & cID & rID & "," & map & "," & i & ",FALSE)")
i = i + 1
Next
'> Convert to values
With rng1
.Value = .Value
End With
End Sub
答案 0 :(得分:1)
我会尝试帮助,因为你表现出努力学习。我将为您提供有关整体VBA编码以及您的问题的一些有用提示。请尝试记住它们。
您的代码难以阅读,因为您的变量命名不佳。在VBA中,单元格与其值之间存在差异。在您的代码中,您有rng1
和rng2
。我看到目前rng1
代表单元格的值,而rng2
代表单元格本身。我不确定你是否有意这样做,但现在你会理解它。如果你的意思是一个单元本身,那么很容易理解命名变量rng2
。但如果你的意思是单元格的值,那么命名变量rng1
会产生误导。这只是为了能够更轻松地阅读代码。由于您将此变量定义为string
,因此我怀疑您希望它接收string
类型的值。因此,您应该将变量命名为与其类型相关的内容,即以str...
或s...
开头的内容,这意味着此变量属于string
类型,例如strValue
或sID
。优选方法是使用str
,因为s
可能与single
类型混淆(VBA中也存在此类数据类型)。您应该将此逻辑应用于您使用的每个变量。字符串 - str...
,长 - lng...
,整数 - int...
,双 - dbl...
,布尔 - bln...
等。一种类型是特定的,你在这里使用它。它是object
类型。对象不仅是对象,还可以分解为多种不同的类型,在代码中也使用range
和workbook
个对象。您可以为他们命名o...
或obj...
,或者通常最好使用更具体的名称,例如rng...
(适用范围)或wb...
(适用于工作簿) )。通常的数据类型变量采用没有Set
子句的值,而对象总是需要Set
才能与某些实际对象相关联,例如范围,工作簿,工作表等。在您的代码中我们看到{{1变量是wb2
。如你所知,这并不好。
因此,在这种情况下,如果您希望string
而不是rng1
,则应重命名string
并学会始终使用此命名约定。同样适用于range
。
在所有wb2
之前,始终使用Option Explicit
作为代码模块中的最顶行。这简单地防止了拼写错误。而这实际上是一条不可或缺的路线。我总是使用它,每个人都应该。执行此操作后,我发现您的代码将无法运行,因为未定义sub
变量。使用cell
,因为单元格实际上是Dim cell As Range
类型的对象。在这种情况下,range
被省略,因为Set
循环为你做了这一点。
现在你的实际问题。
您会发现For Each ... In ... Next
对于确定列数非常有用。这表示从A1到最后使用的单元格的工作表中的区域(实际上是最后使用的列和最后使用的行的交集)。鉴于您的数据跨越A列,当它结束时,右侧没有更多数据不属于任何列,您可以使用Worksheet.UsedRange
获取ActiveSheet.UsedRange.Columns.Count
中的列数,并希望在你的表格中。
我先提到UsedRange
,因为我希望你熟悉它。我们将使用它来解决UsedRange
的问题。因此,我在vlookup
之前建议的第一步是找到包含您ID的单元格。我们应首先vlookup
我们将使用的变量,例如dim
:
Dim rng3 As Range
然后我的建议是找到带有ID的单元格循环遍历A列中的单元格,从A3开始,但不循环直到列的末尾,因为有1m行,但直到我们到达最后一个实际使用的行:
rng3
现在,我们拥有您的ID所在的单元格,我们可以将查找放入:
For Each cell In wb1.ActiveSheet.Range("A3:A" & wb1.ActiveSheet.UsedRange.Rows.Count)
If cell <> "" Then
Set rng3 = cell
Exit For 'we found the value, no need to continue looping, so we exit the For loop
End If
Next 'there is no need to write "cell" after "Next", because VBA knows which loop it is in.
我希望这里没有错别字,因为我没有测试过它。但是,我已经仔细检查了代码,看起来没问题。
答案 1 :(得分:0)
我得到了它:
Sub DAc_lookup_headers()
Dim wb1 As Workbook 'Current text/file
Dim map As String 'reference Map
Dim cID As String 'wb1 look up column A
Dim rID As String 'wb1 starting row number
Dim rng1 As Range 'wb1 Collection header range
Dim i As Long 'Index number per cell in range
Set wb1 = ActiveWorkbook
Set rng1 = wb1.ActiveSheet.[A1:G1]
map = ("'C:\Users\x165422\Desktop\New folder\[Reference.xlsx]Ref'!$A$1:$I$13")
rID = 2 'Row where ID is - will increment + 1 if not found
cID = "A" 'Column where ID is
i = 3 'Starting vlookup Index number - to increment per cell in range
'>Look for ID until value is found
Do
rID = rID + 1
wb1.ActiveSheet.[a1].Value = ("=VLOOKUP(" & cID & rID & "," & map & "," & i & ",FALSE)")
Loop Until wb1.ActiveSheet.[a1].Text <> "#N/A" Or "0"
'> Populate remining headers
For Each cell In rng1
cell.Value = ("=VLOOKUP(" & cID & rID & "," & map & "," & i & ",FALSE)")
i = i + 1
Next
'> Convert to values
With rng1
.Value = .Value
End With
End Sub