我试图自动化Excel文件中的某些功能。
这是我的问题:
表1包含一个字符串是Column" Info",后跟两个空单元格。对于表1中的每一行,我想检查表2,列" Fruit"的值。列#34;信息"如果是这样,我想填写"颜色"和"价格"表1中的空单元格中的表2。
例如,第二行包含单词" bananas",表示" Color" "黄色"和"价格" " 15"应填写表1第2行中的相同列。
不知怎的,这个问题对我来说似乎很简单,但当我开始考虑如何实现这个时,我就陷入了困境。很遗憾,我没有任何代码可供修复。我只是希望这个问题不是太模糊。
我也尝试使用公式,使用MATCH和INDEX来解决这个问题,但我也无法使用它。
答案 0 :(得分:0)
这是一个函数,它将返回ListObject(Table)中找到第一个匹配单词的行。
Public Function MatchFruit(ByVal sInfo As String, ByRef rFruit As Range) As Long
Dim vaSplit As Variant
Dim i As Long, j As Long
Dim rFound As Range
Dim sWhat As String
vaSplit = Split(sInfo, Space(1))
For i = LBound(vaSplit) To UBound(vaSplit)
'strip out non-alpha characters
sWhat = vbNullString
For j = 1 To Len(vaSplit(i))
If Asc(Mid(LCase(vaSplit(i)), j, 1)) >= 97 And Asc(Mid(LCase(vaSplit(i)), j, 1)) <= 122 Then
sWhat = sWhat & Mid(vaSplit(i), j, 1)
End If
Next j
'find the word in the range
Set rFound = Nothing
Set rFound = rFruit.Find(sWhat, , xlValues, xlWhole, , , False)
If Not rFound Is Nothing Then 'if it's found
'return the row in the ListObject
MatchFruit = rFound.Row - rFruit.ListObject.HeaderRowRange.Row
'stop looking
Exit For
End If
Next i
End Function
假设您的第一个表名为tblData,而您的第二个表名为tblFruit,则可以使用
获取颜色=INDEX(tblFruit[Color],MatchFruit([@Info],tblFruit[Fruit]))
和价格类似
=INDEX(tblFruit[Price],MatchFruit([@Info],tblFruit[Fruit]))
长解释
vaSplit
赋值行使用Split
函数将字符串转换为基于分隔符的数组。由于您的样本数据是句子,因此正常分隔符是将其拆分为单词的空间。像
This is some line about apples.
转换为数组
vaSplit(1) This
vaSplit(2) is
vaSplit(3) some
vaSplit(4) line
vaSplit(5) about
vaSplit(6) apples.
接下来,For
循环遍历数组中的每个元素,以查看它是否可以在另一个列表中找到它。使用函数LBound
和Ubound
(下限和上限),因为我们无法确定数组将包含多少元素。
循环中的第一个操作是去除任何无关的字符。为此,我们创建变量sWhat
并将其设置为空。然后我们遍历元素中的所有字符,看看是否有任何超出范围a...z
。基本上,任何字母的内容都会附加到sWhat
,而任何不是(数字,空格,句号)的内容都不会附加到sWhat
。最后apples.
与当前元素相同,所有非字母字符都被删除。在这个例子中,我们永远不会匹配sWhat
因为期间,所以它被剥夺了。
我们有一个好Find
后,我们现在使用rFruit
方法查看该字词是否存在于rFound
范围内。如果是,那么Nothing
将不会是rFound
,我们就会继续前进。
请注意,如果在该范围内找不到该字词,那么Nothing
将为ListObject
,该函数将返回零。
如果找到该单词,该函数将返回找到的行,而不是ListObject
开始的行。这样,函数返回它所在的行,而INDEX
的数据不在工作表上。在合并到Exit For
公式时,这很有用。要使公式返回某些内容,请将该内容分配给公式的名称。
最后,一旦找到匹配项,Set rFound =
行就会停止查看数组。如果您的数据中有多个匹配项,则只会返回第一个匹配项。
<强>疑难解答强>
您可能发现的最可能的错误是,当您希望它返回行号时,该函数将返回零。这很可能意味着它没有在列表中找到任何单词。
如果您确定这两个列表都包含匹配的字词,请按照以下方式对其进行排查:在Debug.Print
行后添加 Set rFound = rFruit.Find(sWhat, , xlValues, xlWhole, , , False)
Debug.Print "." & sWhat & "."
If Not rFound Is Nothing Then 'if it's found
语句。
sWhat
这会将.pears .
打印到立即窗口(VBE中的Ctrl + G以查看立即窗口)。这个词的周期是这样你可以看到任何不可打印的字符(如空格)。如果您尝试将pears
与Trim$()
匹配,则它不会匹配,因为第一个在结尾处有一个空格 - 您可以看到,因为我们在之前和之后停留了一段时间。
如果空格有问题,您可以使用sWhat
上的Debug.Print
函数先删除它们。
使用.paers.
语句,您可能会看到
comtypes
在这种情况下会认识到你有拼写错误。
答案 1 :(得分:0)
迪克和其他可能感兴趣的人。就像我在上一篇关于@ Dick-Kusleika提供的答案的评论中提到的那样,他的答案并没有完全涵盖我最初的问题。虽然它给了我很好的洞察力,并且它完成了用适当的数据填充空单元格的工作,但我真的在寻找可以自动执行的操作,而不必复制粘贴任何公式。因此,我花了一些时间试图解决这个问题,从互联网上获取信息并与一位与我有共同兴趣的同事争吵。最终我设法让它工作! (欢呼!!)
以下是我的解决方案。由于我还是初学者,我可能做了一些本来可以做得更好或更干净的事情。因此,我对您对此的看法非常感兴趣,并希望听到任何评论或提示。
Sub check_fruit()
Dim ws As Excel.Worksheet
Dim lo_Data As Excel.ListObject
Dim lo_Fruit As Excel.ListObject
Dim lr_Data As Excel.ListRow
Dim lr_Fruit As Excel.ListRow
Dim d_Info As Variant
Dim f_Fruit As Variant
Set ws = ThisWorkbook.Worksheets("Exercise")
Set lo_Data = ws.ListObjects("tblData")
Set lo_Fruit = ws.ListObjects("tblFruit")
For Each lr_Data In lo_Data.ListRows
'check if field "Color" is empty in tblData'
If IsEmpty(Intersect(lr_Data.Range, lo_Data.ListColumns("Color").Range).Value) Then
d_Info = Intersect(lr_Data.Range, lo_Data.ListColumns("Info").Range).Value
For Each lr_Fruit In lo_Fruit.ListRows
f_Fruit = Intersect(lr_Fruit.Range, lo_Fruit.ListColumns("Fruit").Range).Value
'check for each row in tblFruit if value for field "Fruit" exists in field "Info" of tblData'
If InStr(1, d_Info, f_Fruit, vbTextCompare) <> 0 Then
Intersect(lr_Data.Range, lo_Data.ListColumns("Color").Range).Value = Intersect(lr_Fruit.Range, lo_Fruit.ListColumns("Color").Range).Value
Intersect(lr_Data.Range, lo_Data.ListColumns("Price").Range).Value = Intersect(lr_Fruit.Range, lo_Fruit.ListColumns("Price").Range).Value
End If
Next lr_Fruit
End If
Next lr_Data
End Sub