【问题标题】:Compare two strings and return matched values?比较两个字符串并返回匹配的值?
【发布时间】:2019-02-17 11:02:48
【问题描述】:

我希望比较两个相邻单元格中的两个字符串。 所有值以逗号分隔。 返回以逗号分隔的匹配值。

值有时会重复多次,并且可以位于字符串的不同部分。我列表中最大的字符串长度是 6264。

例如

Cell X2 = 219728401, 219728401, 219729021, 219734381, 219735301, 219739921

Cell Y2 = 229184121, 219728401, 219729021, 219734333, 216235302, 219735301

Result/Output = 219728401, 219729021, 219735301

我想应用它的单元格不仅限于 X2 和 Y2,它可以是 X 和 Y 列,输出到 Z 列(或我可以指定的列)。

感谢您对此提供的任何帮助,因为我对 Excel 的 VBA 知识有限。

谢谢。

【问题讨论】:

  • 你会考虑把这两个单元格解析成12个吗?
  • 我最大的单元格有很多值,这意味着两个单元格为 500+,我认为这可能是个问题?
  • 现在查看结果。如果您认为它工作正常,请接受。
  • @JGFMK 谢谢你,我试过你的代码,它将匹配输出到 Z 列,但它看起来是将每一行输出添加到下一行。例如第 Z3 行,包括所有匹配项以及在 Z2 中找到的所有匹配项。然后 Z4 包括来自 Z2 和 Z3 等的任何匹配项。

标签: excel vba compare match


【解决方案1】:

如果您现在选择一系列行并运行宏 - 它会为根据 X 和 Y 列输入选择的每一行填充 Z 列。

Sub Macro1()
  ' https://stackoverflow.com/questions/54732564/compare-two-strings-and-return-matched-values
  Dim XString       As String
  Dim YString       As String
  Dim XArray()      As String
  Dim YArray()      As String
  Dim xe            As Variant
  Dim ye            As Variant
  Dim res           As Variant
  Dim ZString       As String
  Dim resCollection As New Collection
  Dim XColumnNumber As Long
  Dim YColumnNumber As Long
  Dim ZColumnNumber As Long
  Dim found         As Boolean
  XColumnNumber = Range("X1").Column
  YColumnNumber = Range("Y1").Column ' Could have done XColumn + 1 ! But if you want F and H it will work too now.
  ZColumnNumber = Range("Z1").Column ' Your result goes here
  Set resCollection = Nothing
  For Each r In Selection.Rows
    XString = ActiveSheet.Cells(r.Row, XColumnNumber).Value
    YString = ActiveSheet.Cells(r.Row, YColumnNumber).Value
    Debug.Print "XString: "; XString
    Debug.Print "YString: "; YString
    XArray = Split(XString, ",")
    YArray = Split(YString, ",")
    For Each xe In XArray
      Debug.Print "xe:"; xe
      For Each ye In YArray
        Debug.Print "ye:"; ye
        If Trim(xe) = Trim(ye) Then
          Debug.Print "Same trimmed"
          found = False
          For Each res In resCollection
            If res = Trim(xe) Then
                found = True
                Exit For
            End If
          Next res
          Debug.Print "Found: "; found
          If Not (found) Then
            resCollection.Add Trim(xe)
            Debug.Print "Adding: "; xe
          End If
        End If
      Next ye
    Next xe
    Debug.Print "resCollection: "; resCollection.Count
    ZString = ""
    For Each res In resCollection
        ZString = ZString & Trim(res) & ", "
    Next res
    If Len(ZString) > 2 Then
      ZString = Left(ZString, Len(ZString) - 2)
    End If
    ActiveSheet.Cells(r.Row, ZColumnNumber).Value = ZString
  Next r
End Sub

注意如果你有 2,1,2 和 2,5,2 并且想要 2,2 然后删除 if Not Found 部分并每次添加。

【讨论】:

  • 感谢您的回复,我已经复制了您的代码,但是在以下行出现语法错误:Dim X2Array as Array 和 Dim Y2Array as Array
  • 编译错误:预期:新名称或类型名称
  • 将 X2Array 调暗为数组 & 将 Y2Array 调暗为数组
  • 请注意:我想应用它的单元格不仅限于 X2 和 Y2,它的 X 和 Y 行,如果可能的话,输出到 Z 列?比较字符串将始终在同一行中。
【解决方案2】:

这是另一个使用 Dictionary 对象来评估匹配的版本。

它还使用数组来加快处理速度——对大型数据集很有用。

请务必按照代码的 cmets 中的说明设置引用,但如果您要分发此代码,您可能更喜欢使用后期绑定。

一个假设是您的所有值都是数字。如果有些包含文本,您可能(或可能不)想要将字典比较模式更改为文本。

Option Explicit
'Set reference to Microsoft Scripting Runtime

Sub MatchUp()
    Dim WS As Worksheet, R As Range
    Dim V, W, X, Y, Z
    Dim D As Dictionary
    Dim I As Long

Set WS = Worksheets("sheet1") 'Change to your desired worksheet
With WS
    'Change `A` to `X` for your stated setup
    Set R = .Range(.Cells(1, "A"), .Cells(.Rows.Count, 1).End(xlUp)).Resize(columnsize:=3)

    'Read range into variant array
    V = R
End With

For I = 2 To UBound(V, 1)
    W = Split(V(I, 1), ",")
    X = Split(V(I, 2), ",")
    V(I, 3) = ""

    'Test and populate third column (in array) if there are matches
    'Will also eliminate any duplicate codes within the data columns
    Set D = New Dictionary
        For Each Y In W
            Y = Trim(Y) 'could be omitted if no leading/trailing spaces
            If Not D.Exists(Y) Then D.Add Y, Y
        Next Y
        For Each Z In X
            Z = Trim(Z)
            If D.Exists(Z) Then V(I, 3) = V(I, 3) & ", " & Z
        Next Z
    V(I, 3) = Mid(V(I, 3), 3)
Next I

R.EntireColumn.Clear
R.EntireColumn.NumberFormat = "@"
R.Value = V 'write the results back to the worksheet, including column 3
R.EntireColumn.AutoFit
End Sub

【讨论】:

  • 感谢您的时间和精力。我试图运行您的解决方案,但是在线(Dim D as Dictionary)我收到错误:“未定义用户定义的类型。”
  • @Brooks 您选择不遵循有关设置参考或启用后期绑定的说明。如果您这样做了,您将不会看到该错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-28
  • 2021-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多