使用 VBA 匹配 excel 中包含字符分隔值的列
Matching with a column containing character-delimited values in excel using VBA
我在 sheet 中的两列中有如下数据。
+------------------+---------------------------------------+
| A | B |
+------------------+---------------------------------------+
| Hector Hall | |
| Guy Gardner | |
| Bart Allen | |
| Kyle Rayner | |
| Dick Grayson | |
| Khalid Nassour | |
| Kent Nelson | |
| Tim Drake | |
| Bat 2 | Dick Grayson; James Gordon |
| James Gordon | |
| Hal Jordan | |
| Robin 2 | Tim Drake; Stephanie Brown |
| Jay Garrick | |
| Jason Todd | |
| Flash 1 | Barry Allen; Wally West |
| GL 2 | Guy Gardner; Kyle Rayner; Jon Stewart |
| Fate 1 | Kent Nelson; Khalid Nassour |
| GL 1 | Alan Scott; Simon Baz |
| Simon Baz | |
| Robin 1 | Dick Grayson; Damien Wayne |
| Alan Scott | |
| Bruce Wayne | |
| Jean Paul Valley | |
| Wally West | |
| Bat 1 | Bruce Wayne; Jean Paul Valley |
+------------------+---------------------------------------+
我正在尝试使用 VBA
代码创建一个 ActiveX 命令按钮,该代码执行以下条件格式:
1) 突出显示 A 中的所有单元格,这些单元格在 B.
中以分号分隔值的形式出现
2) 突出显示 B 中的所有单元格,其分号分隔值在 A.
中不存在
目前,我可以通过在单独的 sheet 中获取所有分号分隔值并将其用于匹配来实现。但它变得棘手,因为 B 中分号分隔值的数量不统一并且可能变化很大。
在 excel VBA 中有更优雅的方法吗?
应该可行
1)
Sub butA()
Dim szyt2 As Worksheet
Dim j As Long, i As Long, k As Long
Dim lastRow As Long
Dim araj1
Dim araj2
Set szyt2 = ThisWorkbook.Sheets("Sheet2")
lastRow = szyt2.Cells(Rows.Count, 1).End(xlUp).row
araj1 = szyt2.Range("A1:A" & lastRow).Value
araj2 = szyt2.Range("B1:B" & lastRow).Value
For i = 1 To UBound(araj2, 1)
If Not (araj2(i, 1) = "") Then
If InStr(1, araj2(i, 1), ";") > 0 Then
ar = Split(araj2(i, 1), ";")
For k = 0 To UBound(ar)
For j = 1 To UBound(araj1, 1)
If araj1(j, 1) = ar(k) Then
szyt2.Cells(j, 1).Interior.ColorIndex = 3
End If
Next
Next
End If
End If
Next
End Sub
2)
Sub butB()
Dim szyt2 As Worksheet
Dim j As Long, i As Long, k As Long
Dim lastRow As Long
Dim araj1
Dim araj2
Set szyt2 = ThisWorkbook.Sheets("Sheet2")
lastRow = szyt2.Cells(Rows.Count, 1).End(xlUp).row
araj1 = szyt2.Range("A1:A" & lastRow).Value
araj2 = szyt2.Range("B1:B" & lastRow).Value
counter = 0
For i = 1 To UBound(araj2, 1)
If Not (araj2(i, 1) = "") Then
If InStr(1, araj2(i, 1), ";") > 0 Then
ar = Split(araj2(i, 1), ";")
For k = 0 To UBound(ar)
For j = 1 To UBound(araj1, 1)
If araj1(j, 1) = ar(k) Then
counter = counter + 1
End If
Next
If counter > 0 Then Exit For
Next
If counter > 0 Then
szyt2.Cells(i, 2).Interior.ColorIndex = 3
End If
End If
End If
counter = 0
Next
End Sub
试试这个:
Sub rrrrr()
Dim dicA As Object: Set dicA = CreateObject("Scripting.Dictionary")
Dim dicB As Object: Set dicB = CreateObject("Scripting.Dictionary")
Dim lastRow&, cl As Range, key$, keyA, keyB, x
With ActiveSheet 'replace with source
lastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
'get dictionary for column A
For Each cl In .Range(.[A1], .Cells(lastRow, "A"))
If Trim(cl.Value2) <> "" Then
key = Trim(cl.Value2)
If Not dicA.exists(key) Then
dicA.Add key, cl.Address(0, 0)
Else
dicA(key) = dicA(key) & "," & cl.Address(0, 0)
End If
End If
Next cl
'get dictionary for column B
For Each cl In .Range(.[B1], .Cells(lastRow, "B"))
If Trim(cl.Value2) <> "" Then
For Each x In Split(cl.Value2, ";")
key = Trim(x)
If Not dicB.exists(key) Then
dicB.Add key, cl.Address(0, 0)
Else
dicB(key) = dicB(key) & "," & cl.Address(0, 0)
End If
Next x
End If
Next cl
'keys in A not exist in B
For Each keyA In dicA
If Not dicB.exists(keyA) Then
.Range(dicA(keyA)).Interior.Color = vbYellow
End If
Next keyA
'keys in B not exist in A, and add comment what exact key not exists in B
For Each keyB In dicB
If Not dicA.exists(keyB) Then
With .Range(dicB(keyB))
.Interior.Color = vbYellow
.ClearComments: .AddComment:
With .Comment
.Text "missed: " & keyB
.Shape.TextFrame.AutoSize = 1
.Shape.TextFrame.Characters.Font.Bold = 1
.Shape.Fill.ForeColor.RGB = RGB(58, 82, 184)
.Shape.AutoShapeType = msoShapeRoundedRectangle
.Shape.TextFrame.Characters.Font.ColorIndex = 2
End With
End With
End If
Next keyB
End With
End Sub
演示:
我在 sheet 中的两列中有如下数据。
+------------------+---------------------------------------+
| A | B |
+------------------+---------------------------------------+
| Hector Hall | |
| Guy Gardner | |
| Bart Allen | |
| Kyle Rayner | |
| Dick Grayson | |
| Khalid Nassour | |
| Kent Nelson | |
| Tim Drake | |
| Bat 2 | Dick Grayson; James Gordon |
| James Gordon | |
| Hal Jordan | |
| Robin 2 | Tim Drake; Stephanie Brown |
| Jay Garrick | |
| Jason Todd | |
| Flash 1 | Barry Allen; Wally West |
| GL 2 | Guy Gardner; Kyle Rayner; Jon Stewart |
| Fate 1 | Kent Nelson; Khalid Nassour |
| GL 1 | Alan Scott; Simon Baz |
| Simon Baz | |
| Robin 1 | Dick Grayson; Damien Wayne |
| Alan Scott | |
| Bruce Wayne | |
| Jean Paul Valley | |
| Wally West | |
| Bat 1 | Bruce Wayne; Jean Paul Valley |
+------------------+---------------------------------------+
我正在尝试使用 VBA
代码创建一个 ActiveX 命令按钮,该代码执行以下条件格式:
1) 突出显示 A 中的所有单元格,这些单元格在 B.
中以分号分隔值的形式出现2) 突出显示 B 中的所有单元格,其分号分隔值在 A.
中不存在目前,我可以通过在单独的 sheet 中获取所有分号分隔值并将其用于匹配来实现。但它变得棘手,因为 B 中分号分隔值的数量不统一并且可能变化很大。
在 excel VBA 中有更优雅的方法吗?
应该可行
1)
Sub butA()
Dim szyt2 As Worksheet
Dim j As Long, i As Long, k As Long
Dim lastRow As Long
Dim araj1
Dim araj2
Set szyt2 = ThisWorkbook.Sheets("Sheet2")
lastRow = szyt2.Cells(Rows.Count, 1).End(xlUp).row
araj1 = szyt2.Range("A1:A" & lastRow).Value
araj2 = szyt2.Range("B1:B" & lastRow).Value
For i = 1 To UBound(araj2, 1)
If Not (araj2(i, 1) = "") Then
If InStr(1, araj2(i, 1), ";") > 0 Then
ar = Split(araj2(i, 1), ";")
For k = 0 To UBound(ar)
For j = 1 To UBound(araj1, 1)
If araj1(j, 1) = ar(k) Then
szyt2.Cells(j, 1).Interior.ColorIndex = 3
End If
Next
Next
End If
End If
Next
End Sub
2)
Sub butB()
Dim szyt2 As Worksheet
Dim j As Long, i As Long, k As Long
Dim lastRow As Long
Dim araj1
Dim araj2
Set szyt2 = ThisWorkbook.Sheets("Sheet2")
lastRow = szyt2.Cells(Rows.Count, 1).End(xlUp).row
araj1 = szyt2.Range("A1:A" & lastRow).Value
araj2 = szyt2.Range("B1:B" & lastRow).Value
counter = 0
For i = 1 To UBound(araj2, 1)
If Not (araj2(i, 1) = "") Then
If InStr(1, araj2(i, 1), ";") > 0 Then
ar = Split(araj2(i, 1), ";")
For k = 0 To UBound(ar)
For j = 1 To UBound(araj1, 1)
If araj1(j, 1) = ar(k) Then
counter = counter + 1
End If
Next
If counter > 0 Then Exit For
Next
If counter > 0 Then
szyt2.Cells(i, 2).Interior.ColorIndex = 3
End If
End If
End If
counter = 0
Next
End Sub
试试这个:
Sub rrrrr()
Dim dicA As Object: Set dicA = CreateObject("Scripting.Dictionary")
Dim dicB As Object: Set dicB = CreateObject("Scripting.Dictionary")
Dim lastRow&, cl As Range, key$, keyA, keyB, x
With ActiveSheet 'replace with source
lastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
'get dictionary for column A
For Each cl In .Range(.[A1], .Cells(lastRow, "A"))
If Trim(cl.Value2) <> "" Then
key = Trim(cl.Value2)
If Not dicA.exists(key) Then
dicA.Add key, cl.Address(0, 0)
Else
dicA(key) = dicA(key) & "," & cl.Address(0, 0)
End If
End If
Next cl
'get dictionary for column B
For Each cl In .Range(.[B1], .Cells(lastRow, "B"))
If Trim(cl.Value2) <> "" Then
For Each x In Split(cl.Value2, ";")
key = Trim(x)
If Not dicB.exists(key) Then
dicB.Add key, cl.Address(0, 0)
Else
dicB(key) = dicB(key) & "," & cl.Address(0, 0)
End If
Next x
End If
Next cl
'keys in A not exist in B
For Each keyA In dicA
If Not dicB.exists(keyA) Then
.Range(dicA(keyA)).Interior.Color = vbYellow
End If
Next keyA
'keys in B not exist in A, and add comment what exact key not exists in B
For Each keyB In dicB
If Not dicA.exists(keyB) Then
With .Range(dicB(keyB))
.Interior.Color = vbYellow
.ClearComments: .AddComment:
With .Comment
.Text "missed: " & keyB
.Shape.TextFrame.AutoSize = 1
.Shape.TextFrame.Characters.Font.Bold = 1
.Shape.Fill.ForeColor.RGB = RGB(58, 82, 184)
.Shape.AutoShapeType = msoShapeRoundedRectangle
.Shape.TextFrame.Characters.Font.ColorIndex = 2
End With
End With
End If
Next keyB
End With
End Sub
演示: