找回密码
 注册
搜索
系统gho:最纯净好用系统下载站投放广告、加入VIP会员,请联系 微信:wuyouceo
查看: 188|回复: 13

vba查询excel工作表内有没有重复的单元格,只能找出第一对重复的

[复制链接]
发表于 昨天 20:56 | 显示全部楼层 |阅读模式
本帖最后由 likeyouli 于 2026-3-22 18:47 编辑

别再用ai答复我了,我这是分享,不是求助,ai回答的我都不满意,我写的每个代码我都理解其意义。
vba就是要活学活用,我为啥分享这个?因为这个是我的基础分享,这绝不是为了单纯查询重复,而是为了代码后边的部分(因具体需求不同不再分享)。一开始觉得这个代码很简单,无非数组和字典,但真写起来,竟然用了两个正则,用了union,用了find、findnext等,甚至我也不知道inputbox输入的内容为字符串自带引号,比如输入a1传递给变量quyu,可以用range(quyu),因为这就代表了range("a1"),而不需要输入"a1";输入b2:c390就代表range("b2:c390"),总之,写这么简单的代码竟然费了我好几遍精力,所以才想起来分享。

Sub 查询工作表内单元格有没有重复值()
Dim d As New Dictionary, dizhi As Range, r As New RegExp, dizhi1 As Range
'两次使用正则表达式判定输入的格式是否正确
'Set r = CreateObject("VBScript.RegExp")
kaishi:
quyu = InputBox("请输入活动工作表的一个单元格(如a1,用currentregion)或输入一个区域(b2:c390):", "请输入", "b2:c101")
Stop
r.Global = True
r.Pattern = "^[a-zA-Z]\d+$"
If r.Test(quyu) Then linshi = 3 Else linshi = 0
r.Pattern = "^[a-zA-Z]\d+:[a-zA-Z]\d+$"
If Not (r.Test(quyu)) And linshi = 0 Then MsgBox "输入格式错误,请重新输入": GoTo kaishi
If r.Test(quyu) Then
    Range(quyu).Select
    MsgBox "请查看选中的区域"
    arr = Range(quyu)
    For hang = LBound(arr) To UBound(arr)
        For lie = LBound(arr, 2) To UBound(arr, 2)
            If d.Exists(arr(hang, lie)) And arr(hang, lie) <> "" Then
            Set dizhi = Range(quyu).Find(arr(hang, lie))
            Set dizhi1 = Range(quyu).FindNext(dizhi)
              MsgBox "存在重复单元格,查询到的第一个重复单元格内容为""" & arr(hang, lie) & _
              """;地址为" & dizhi.Address(0, 0) & "和" & dizhi1.Address(0, 0): Union(dizhi, dizhi1).Select: Exit Sub
            Else
              d(arr(hang, lie)) = ""
             End If
        Next lie
    Next hang
'    Range(quyu).Interior.Pattern = xlPatternNone
Else
    Range(quyu).CurrentRegion.Select
    MsgBox "请查看选中的颜色区域"
   arr = Range(quyu).CurrentRegion
      For hang = LBound(arr) To UBound(arr)
        For lie = LBound(arr, 2) To UBound(arr, 2)
            If d.Exists(arr(hang, lie)) And arr(hang, lie) <> "" Then
            Set dizhi = Range(quyu).CurrentRegion.Find(arr(hang, lie))
            Set dizhi1 = Range(quyu).CurrentRegion.FindNext(dizhi)
              MsgBox "存在重复单元格,查询到的第一个重复单元格内容为""" & arr(hang, lie) & _
              """;地址为" & dizhi.Address(0, 0) & "和" & dizhi1.Address(0, 0): Union(dizhi, dizhi1).Select: Exit Sub
            Else
              d(arr(hang, lie)) = ""
             End If
        Next lie
    Next hang
   ' Range(quyu).CurrentRegion.Interior.Pattern = xlPatternNone
End If
MsgBox "恭喜,未发现重复单元格,代码结束!!"
End Sub



发表于 昨天 21:14 | 显示全部楼层
没看内容,我说一下逻辑:
1.分别返回有数据的最左最右列、最上最下行
2.循环挨个从左上单元格开始往下往右直到右下角单元格查找
3.将2获取到的值再与循环挨个从左上到右下角单元格比对
完毕...
回复

使用道具 举报

发表于 昨天 21:14 | 显示全部楼层
谢谢,vba高手啊
回复

使用道具 举报

发表于 昨天 21:30 | 显示全部楼层
ai可以编写,还可以修改
回复

使用道具 举报

 楼主| 发表于 昨天 21:33 | 显示全部楼层
本帖最后由 likeyouli 于 2026-3-21 21:37 编辑

字典不会引用的
可以加上 set d = createobject("scripting.dictionary")   否则报错;
同理正则不会引用的,直接将Set r = CreateObject("VBScript.RegExp") 前边的 ' 去掉即可(即解除注释)
回复

使用道具 举报

发表于 昨天 21:37 | 显示全部楼层
excel 能直接显示重复单元格

点评

是的 ,条件格式里就能设置,,但vba更灵活,我想让代码怎么跑就怎么跑; 另外,查重复不是目的,这只是我代码一部分。我想用find查询,因为find只能查询到第一个待搜索内容,然后表格之间相加,然后自动更新表格数  详情 回复 发表于 昨天 21:53
回复

使用道具 举报

发表于 昨天 21:40 | 显示全部楼层
我来帮着用AI改(其实最好有个现成的例子,这样出结果快):
  1. Sub 查找所有重复值()
  2.     Dim d As Object, arr() As String
  3.     Dim rng As Range, cell As Range
  4.     Dim quyu As String, i As Long
  5.     Dim hasDuplicates As Boolean
  6.    
  7.     '创建字典对象
  8.     Set d = CreateObject("Scripting.Dictionary")
  9.    
  10.     '获取用户输入的区域
  11.     On Error Resume Next
  12.     Set rng = Application.InputBox( _
  13.         "请选择要检查的区域:", _
  14.         "选择区域", _
  15.         Selection.Address, _
  16.         Type:=8)
  17.     On Error GoTo 0
  18.    
  19.     If rng Is Nothing Then Exit Sub  '用户取消
  20.    
  21.     '检查重复值
  22.     For Each cell In rng
  23.         If Len(Trim(cell.Value)) > 0 Then
  24.             If d.Exists(cell.Value) Then
  25.                 d(cell.Value) = d(cell.Value) & ", " & cell.Address(0, 0)
  26.                 hasDuplicates = True
  27.             Else
  28.                 d(cell.Value) = cell.Address(0, 0)
  29.             End If
  30.         End If
  31.     Next cell
  32.    
  33.     If hasDuplicates Then
  34.         '显示所有重复值
  35.         ReDim arr(1 To d.Count, 1 To 3)
  36.         i = 0
  37.         
  38.         For Each cell In rng
  39.             If Len(Trim(cell.Value)) > 0 Then
  40.                 Dim addresses As String
  41.                 addresses = d(cell.Value)
  42.                
  43.                 '如果地址中包含逗号,说明有重复
  44.                 If InStr(addresses, ",") > 0 Then
  45.                     i = i + 1
  46.                     arr(i, 1) = cell.Value
  47.                     arr(i, 2) = addresses
  48.                     arr(i, 3) = Len(Split(addresses, ","))  '重复次数
  49.                     
  50.                     '高亮显示重复单元格
  51.                     cell.Interior.Color = RGB(255, 255, 0)
  52.                 End If
  53.             End If
  54.         Next cell
  55.         
  56.         '在工作表中显示结果
  57.         Dim ws As Worksheet
  58.         Set ws = Worksheets.Add
  59.         ws.Name = "重复值报告"
  60.         
  61.         With ws
  62.             .Range("A1:C1") = Array("重复内容", "所在位置", "重复次数")
  63.             .Range("A2").Resize(i, 3) = arr
  64.             .Columns.AutoFit
  65.             .Rows(1).Font.Bold = True
  66.         End With
  67.         
  68.         MsgBox "共发现 " & i & " 个重复值,已在新建的工作表中显示。"
  69.     Else
  70.         MsgBox "恭喜!未发现重复值。", vbInformation
  71.     End If
  72.    
  73.     '清除高亮
  74.     rng.Interior.ColorIndex = xlNone
  75. End Sub
复制代码
回复

使用道具 举报

发表于 昨天 21:43 | 显示全部楼层
本帖最后由 a66 于 2026-3-22 08:11 编辑
  1. Sub 查询工作表内单元格有没有重复值()
  2.     Dim d As Object
  3.     Dim quyu As String
  4.     Dim r As Object
  5.     Dim arr As Variant
  6.     Dim hang As Long, lie As Long
  7.     Dim firstAddr As String, secondAddr As String
  8.     Dim targetRange As Range
  9.    
  10.     ' 创建字典和正则对象
  11.     Set d = CreateObject("Scripting.Dictionary")
  12.     Set r = CreateObject("VBScript.RegExp")
  13.    
  14.     ' 设置字典比较模式为文本不区分大小写(可选)
  15.     d.CompareMode = vbTextCompare
  16.    
  17. input_retry:
  18.     quyu = InputBox("请输入活动工作表的一个单元格(如A1,将使用CurrentRegion)或一个区域(如B2:C390):", "输入区域", "B2:C101")
  19.    
  20.     ' 用户取消
  21.     If quyu = "" Then Exit Sub
  22.    
  23.     ' 正则验证输入格式
  24.     r.Global = True
  25.     r.IgnoreCase = True
  26.    
  27.     ' 情况1:单个单元格(如 A1)
  28.     r.Pattern = "^[a-z]+\d+$"
  29.     If r.Test(quyu) Then
  30.         Set targetRange = Range(quyu).CurrentRegion
  31.         MsgBox "将检查区域:" & targetRange.Address, vbInformation
  32.     Else
  33.         ' 情况2:区域(如 B2:D100)
  34.         r.Pattern = "^[a-z]+\d+:[a-z]+\d+$"
  35.         If r.Test(quyu) Then
  36.             Set targetRange = Range(quyu)
  37.             MsgBox "将检查区域:" & targetRange.Address, vbInformation
  38.         Else
  39.             MsgBox "输入格式错误!请使用类似 A1 或 B2:C100 的格式。", vbExclamation
  40.             GoTo input_retry
  41.         End If
  42.     End If
  43.    
  44.     ' 将区域值读入数组(提升效率)
  45.     If targetRange.Cells.Count = 1 Then
  46.         ReDim arr(1 To 1, 1 To 1)
  47.         arr(1, 1) = targetRange.Value
  48.     Else
  49.         arr = targetRange.Value
  50.     End If
  51.    
  52.     ' 遍历数组
  53.     For hang = LBound(arr, 1) To UBound(arr, 1)
  54.         For lie = LBound(arr, 2) To UBound(arr, 2)
  55.             Dim cellValue As Variant
  56.             cellValue = arr(hang, lie)
  57.             
  58.             ' 跳过空单元格
  59.             If Not IsEmpty(cellValue) And cellValue <> "" Then
  60.                 ' 如果字典中已存在该值 → 找到第一对重复!
  61.                 If d.Exists(cellValue) Then
  62.                     firstAddr = d(cellValue) ' 首次出现的地址
  63.                     secondAddr = targetRange.Cells(hang, lie).Address(0, 0) ' 当前地址
  64.                     
  65.                     ' 报告结果
  66.                     MsgBox "存在重复单元格!" & vbCrLf & _
  67.                            "内容:""" & cellValue & """" & vbCrLf & _
  68.                            "位置:" & firstAddr & " 和 " & secondAddr, vbCritical
  69.                     
  70.                     ' 选中两个单元格
  71.                     Union(Range(firstAddr), Range(secondAddr)).Select
  72.                     
  73.                     ' 可选:高亮显示(取消注释下一行)
  74.                     ' Union(Range(firstAddr), Range(secondAddr)).Interior.Color = RGB(255, 255, 0)
  75.                     
  76.                     Exit Sub ' 仅找第一对,立即退出
  77.                 Else
  78.                     ' 记录首次出现的地址
  79.                     d(cellValue) = targetRange.Cells(hang, lie).Address(0, 0)
  80.                 End If
  81.             End If
  82.         Next lie
  83.     Next hang
  84.    
  85.     ' 若执行到此处,说明无重复
  86.     MsgBox "恭喜!未发现重复的非空单元格。", vbInformation
  87. End Sub
复制代码


回复

使用道具 举报

 楼主| 发表于 昨天 21:53 | 显示全部楼层
newswan 发表于 2026-3-21 21:37
excel 能直接显示重复单元格

是的 ,条件格式里就能设置,,但vba更灵活,我想让代码怎么跑就怎么跑;
另外,查重复不是目的,这只是我代码一部分。我想用find查询,因为find只能查询到第一个待搜索内容,然后表格之间相加,然后自动更新表格数据....

点评

很久没用 vba , 已经忘记了 刚才问 ai 用字典判断有没有重复  详情 回复 发表于 10 小时前
回复

使用道具 举报

发表于 13 小时前 | 显示全部楼层
第一个查找FindNext区域与Find区域有变化,后面也没有判断地址是否与首地址相同。
Set dizhi = Range(quyu).Find(arr(hang, lie))
Set dizhi1 = Range(quyu).CurrentRegion.FindNext(dizhi)


第二个查找区域相同,但也没有判断地址。
Set dizhi = Range(quyu).CurrentRegion.Find(arr(hang, lie))
Set dizhi1 = Range(quyu).CurrentRegion.FindNext(dizhi)

  1. '示例
  2. Set 查找区域 = 工作表.UsedRange
  3. Set 查找单元格=工作表.Cells(1,3)
  4. 查找内容=查找单元格.Value

  5. Set 内容单元格 = 查找区域.Find(查找内容)
  6. 内容单元格地址 = 内容单元格.Address
  7. Set 找下一个单元格 = 查找区域.FindNext(内容单元格)
  8. If Not 找下一个单元格 Is Nothing And 找下一个单元格.Address <> 内容单元格地址
  9.         找到第一个单元格地址=找下一个单元格.Address
  10. End If
复制代码

点评

感谢提醒,“第一个查找FindNext区域与Find区域有变化” ,已经改正。 后边这句“没有判断地址是否与首地址相同” 我没有理解什么意思...  详情 回复 发表于 5 小时前
回复

使用道具 举报

发表于 10 小时前 | 显示全部楼层
likeyouli 发表于 2026-3-21 21:53
是的 ,条件格式里就能设置,,但vba更灵活,我想让代码怎么跑就怎么跑;
另外,查重复不是目的,这只是 ...

很久没用 vba , 已经忘记了
刚才问 ai
  1. Dim dict As Object
  2. Set dict = CreateObject("Scripting.Dictionary")
  3. 新增        dict.Add "A001", "苹果"        向字典添加一个键值对
  4. 赋值/修改        dict("A001") = "香蕉"        如果键存在则修改,不存在则新增
  5. 判断是否存在        if dict.Exists("A001") Then        检查某个键是否已经在字典里
  6. 读取值        msgbox dict("A001")        通过键获取对应的数值
  7. 删除单个        dict.Remove "A001"        删除特定的键值对
  8. 清空        dict.RemoveAll        一键清空字典
复制代码

用字典判断有没有重复
回复

使用道具 举报

发表于 10 小时前 | 显示全部楼层
ai 写了一个样本
  1. Sub RecordDuplicatesAndAddresses()
  2.     Dim dict As Object
  3.     Set dict = CreateObject("Scripting.Dictionary")
  4.    
  5.     Dim i As Long
  6.     Dim lastRow As Long
  7.     Dim key As String
  8.     Dim addr As String
  9.    
  10.     ' 获取A列最后一行
  11.     lastRow = Cells(Rows.Count, 1).End(xlUp).Row
  12.    
  13.     ' 1. 遍历数据并记录
  14.     For i = 2 To lastRow
  15.         key = Cells(i, 1).Value
  16.         addr = Cells(i, 1).Address(False, False) ' 获取如 "A2" 格式的地址
  17.         
  18.         If dict.Exists(key) Then
  19.             ' 如果已经存在,就在原有地址后面加上逗号和新地址
  20.             dict(key) = dict(key) & ", " & addr
  21.         Else
  22.             ' 如果是第一次出现,直接记录地址
  23.             dict(key) = addr
  24.         End If
  25.     Next i
  26.    
  27.     ' 2. 将结果输出到 D 列和 E 列
  28.     Dim k As Variant
  29.     Dim r As Long: r = 2
  30.    
  31.     ' 清理输出区域
  32.     Range("D2:E" & Rows.Count).ClearContents
  33.    
  34.     For Each k In dict.Keys
  35.         ' 只有当地址中包含逗号时,说明出现了至少两次(即重复)
  36.         If InStr(dict(k), ",") > 0 Then
  37.             Cells(r, 4).Value = k           ' 重复的值
  38.             Cells(r, 5).Value = dict(k)     ' 所有的单元格地址
  39.             r = r + 1
  40.         End If
  41.     Next k
  42.    
  43.     MsgBox "完成!已在 D:E 列记录重复项及其位置。"
  44. End Sub
复制代码
回复

使用道具 举报

 楼主| 发表于 5 小时前 | 显示全部楼层
本帖最后由 likeyouli 于 2026-3-22 19:05 编辑
cutebe 发表于 2026-3-22 10:04
第一个查找FindNext区域与Find区域有变化,后面也没有判断地址是否与首地址相同。

感谢提醒,“第一个查找FindNext区域与Find区域有变化” ,已经改正。
  后边这句“没有判断地址是否与首地址相同” 我没有理解什么意思... 又看了下你发的代码,我既然确定是重复了(用字典判断的),所以findnext查找的单元格地址肯定与第一个查找的地址不同,所以根本不需要判断。你所谓的需要判断,是指只能查找出一个(即没有重复的),才需要判断一下。


   我费了很大劲、连用两个正则表达式,就是为了选择工作表的哪个区域作为查询有没有重复的区域,很多ai用的currentregion,Excel自带的查重复是用的selection,这两个我都不满意。
回复

使用道具 举报

发表于 5 小时前 | 显示全部楼层
学习一下
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|捐助支持| 无忧启动 ( 闽ICP备05002490号-1|闽公网安备35020302032614号 )

GMT+8, 2026-3-22 23:48

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表