根据其他表格填充单元格

时间:2017-01-24 14:31:00

标签: excel vba excel-vba

我试图自动化Excel文件中的某些功能。

这是我的问题:

simplified example

表1包含一个字符串是Column" Info",后跟两个空单元格。对于表1中的每一行,我想检查表2,列" Fruit"的值。列#34;信息"如果是这样,我想填写"颜色"和"价格"表1中的空单元格中的表2。

例如,第二行包含单词" bananas",表示" Color" "黄色"和"价格" " 15"应填写表1第2行中的相同列。

不知怎的,这个问题对我来说似乎很简单,但当我开始考虑如何实现这个时,我就陷入了困境。很遗憾,我没有任何代码可供修复。我只是希望这个问题不是太模糊。

我也尝试使用公式,使用MATCH和INDEX来解决这个问题,但我也无法使用它。

2 个答案:

答案 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循环遍历数组中的每个元素,以查看它是否可以在另一个列表中找到它。使用函数LBoundUbound(下限和上限),因为我们无法确定数组将包含多少元素。

循环中的第一个操作是去除任何无关的字符。为此,我们创建变量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以查看立即窗口)。这个词的周期是这样你可以看到任何不可打印的字符(如空格)。如果您尝试将pearsTrim$()匹配,则它不会匹配,因为第一个在结尾处有一个空格 - 您可以看到,因为我们在之前和之后停留了一段时间。

如果空格有问题,您可以使用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