ExcelTip.Net留存知识帖 ---【注:附件之前被网盘供应商清空后,现已修复-现已修复-现已修复为本地下载!】
现在位置:首页 > E文精选 > Excel VBA > 查找单元格并上色的几种方法浅析

查找单元格并上色的几种方法浅析

作者:绿色风 分类: 时间:2022-08-17 浏览:285
楼主
xmyjk
问题:在表中查找所需的内容的单元格,并上色,如下图。
      
 
      
问题.rar


     解答如下,见后分解。
2楼
xmyjk
解答:对于这个问题,大家肯定会想到,很简单的,就是把区域所有的单元格找一遍,记录找到的,上色不就完了。
      
这就是第一种方法zaezhong的历遍单元格法

  1. Sub test()
  2.     Dim rng As Range, Adds$, i%
  3.     For Each rng In [a1].CurrentRegion '历遍查找区域的所有单元格
  4.         If rng = "我要的" Then Adds = Adds & rng.Address(0, 0) & "," '如果找到,用ADDS变量记录其地址,每个记录用“,”进行间隔
  5.     Next
  6.     With Range(Left$(Adds, Len(Adds) - 1)) '用RANGE对象控制所找到的单元格
  7.         For i = 1 To .Areas.Count '历遍所找到的单元格
  8.             .Areas(i).Interior.ColorIndex = 46 ' 对每个单元格上色
  9.         Next
  10.     End With
  11. End Sub


1.历遍单元格法.rar


   这种方法需要历遍所有的单元格对象,速度较慢(由于研究要求用RANGE对象控制,zaezhong老师多做了个循环,不然在IF那里历遍时就可以上色了,还会更快的)

    那有没快的方法呢,有人肯定会说,用EXCEL自身的查找功能录个宏不就行了,是的,这也是一个很好的办法,见下楼:
3楼
xmyjk
这就是第二种方法zzmxy的FIND法
  1. Sub zz()
  2.     FindStr$ = Application.InputBox("请输入要查找的内容:", , "我要的") '输入要查找的值
  3.     Set Rng = ActiveSheet.UsedRange.Find(FindStr, LookIn:=xlValues) '对表进行查找
  4.     If Rng Is Nothing Then Exit Sub '如找不到,即退出程序
  5.     Set Arr = Rng '用ARR变量取得找到的第一个单元格
  6.     StartAdd = Rng.Address '用STARTADD变量取得找到的第一个单元格的地址
  7.     Do '开始循环查找后续的单元格
  8.         Set Arr = Union(Arr, Rng) '用UNION函数控制所有找到的单元格,UNION的做法就类似按住键盘CTRL键然后点击所需单元格的控制方式
  9.         Set Rng = ActiveSheet.UsedRange.FindNext(Rng) '查找下一个符合条件的单元格
  10.     Loop While StartAdd <> Rng.Address '如查找到的单元格的地址与第一个单元格的地址相同,就退出循环
  11.     Arr.Interior.ColorIndex = 46 '对所有找到的单元格上色
  12. End Sub

2.FIND法.rar


     这种方法的效率明显加快了很多,因为FIND方法能显著的减少循环次数,加快了效率。这种方法在数据源少的时候,效率非常高。缺点就是在查找的过程时,还是需要对单元格对象进行操作,这样的操作还是比较费时的,有什么解决办法呢?

    有的,把单元格的数值全部倒入数值再进行查找不就完了。见楼下:
4楼
xmyjk
第三种办法:xmyjk的数组法
  1. Sub text1()
  2. Dim arr, i As Long, j As Long, brr() As String, m As Long, res As String, t As Single

  3. Application.DisplayAlerts = False '关闭屏幕显示
  4. t = Timer
  5. m = 0 '计数器归零
  6. arr = Range(Cells(1, 1), Cells([a65536].End(3).Row, [iv1].End(xlToLeft).Column)).Value '将区域导入数组ARR
  7. For i = LBound(arr, 1) To UBound(arr, 1) '历遍数组
  8.    For j = LBound(arr, 2) To UBound(arr, 2) '查找所需数据
  9.        If arr(i, j) = "我要的" Then '如果找到
  10.            m = m + 1 '计数器加1
  11.            ReDim Preserve brr(1 To m) '增加结果数组的维度
  12.            brr(m) = Chr(j + 64) & i '将找到的地址进行转换成类似A1格式并储存进结果数组
  13.        End If
  14.    Next
  15. Next

  16. res = Join(brr, ",") '将结果数组合并成字符串,并以","为间隔
  17. Range(res).Interior.ColorIndex = 46 '使用RANGE对象控制找到的单元格,并进行上色
  18. Application.DisplayAlerts = True '开启屏幕显示
  19. MsgBox Timer - t & "秒"

  20. End Sub

3.数组法.rar


    但是,数值法还是没法有效的减少循环次数,因此如果在少数据量时候,FIND法略快。但是如果随着数据量的增加,数值法由于不需操作对象进行查找,仅仅在内存中查找数值速度明显的加快了
   
    大家可以试看看如下附件,3000多个数据,同样使用UNION方式控制单元格,用FIND和数组查找的效率区别,在我的老机子上,FIND法大概要14秒,数组法大概10秒。

   
4.对比FIND与数组.rar

还要10几秒钟啊,估计还是有些网友会说,还有没更快的法子啊,呵呵有的,就如同查找空行最快的方法是AUTOFILTER一样,EXCEL总是给我们惊喜,条件格式法
5楼
xmyjk
第四方法xmyjk的条件格式法(前提,必须要03版以上的EXCEL,03版只支持三个条件格式,据说10版支持60几个条件格式,如果需要上色类别不多,可以使用这个方法)
  1. Sub 宏1()
  2.     Dim t As Single
  3.    
  4.     Application.DisplayAlerts = False '关闭屏幕显示
  5.     t = Timer
  6.     Cells.FormatConditions.Delete '清楚表中原来的条件格式
  7.    
  8.     With Cells(1, 1).CurrentRegion.FormatConditions.Add(Type:=xlCellValue, Operator:=xlEqual, Formula1:="=""我要的""") '把所要查找的值做成条件格式
  9.         .Interior.ColorIndex = 46 '条件格式即为上色
  10.     End With
  11.    
  12.     Application.DisplayAlerts = True '开启屏幕显示
  13.    
  14.     MsgBox Timer - t & "秒"
  15. End Sub

5.条件格式法解答.rar


    条件格式法的效率显著较高,3000多个所需查找数值并上色,仅仅花了不到0.15秒。且代码简单,录个宏改改就行了。缺点就是,类别不能多,不然要增加很多条件格式,且对条件格式数量也是有限制的。
6楼
xmyjk
最后,问题圆满解决了,附送研究整理完的上色程序供大家参考,再附送一个数组查找的衍生方法:数组+字典的上色法(不需两个数组,但速度比双数组慢,调用外部对象毕竟满,好处就是不用反复的扩充结果数组的维度简化程序)。

   以上供大家学习参考,非科班出身,欢迎指点拍砖。
7.研究整理后程序.rar
6.1数组+1字典法.rar
7楼
xmyjk
楼上指教的是,确实RANGE法有这个缺点,因此四楼的附件,我用UNION的方法做,没有用RANGE的方法做去做
用RANGE做的方法的初衷,是因为采集的那个求助贴的要求,因此,我们几个人都是按照RANGE来回答的。

四楼UNION做的代码如下
  1. Sub text1()
  2. Dim arr, i As Long, j As Long, m As Long, t As Single, rng As Range

  3. Application.DisplayAlerts = False
  4. t = Timer
  5. m = 0
  6. arr = Range(Cells(1, 1), Cells([a65536].End(3).Row, [iv1].End(xlToLeft).Column)).Value
  7. For i = LBound(arr, 1) To UBound(arr, 1)
  8.    For j = LBound(arr, 2) To UBound(arr, 2)
  9.        If arr(i, j) = "我要的" Then
  10.            m = m + 1
  11.            If m = 1 Then
  12.                Set rng = Cells(i, j)
  13.            Else
  14.                Set rng = Union(rng, Cells(i, j))
  15.            End If
  16.        End If
  17.    Next
  18. Next

  19. rng.Interior.ColorIndex = 46
  20. Application.DisplayAlerts = True
  21. MsgBox Timer - t & "秒"

  22. End Sub


8楼
研究研究

字符串长度在255内 我已经解决了啊
第2个问题26个字母是个问题。但当时对方没有提出超过26列的要求。所以暂时没有考虑在其中
9楼
xmyjk
楼上误解微软的说明文件了。

UNION(RANGE1,RANGE2,...RANGE30),UNION指的是一次仅仅可操作30个range

而我们用的办法是,A单元格和B用UNION得到的区域后再与C单元格UNION,不会突破UNION同时操作30个区域的限制。

你看看以下代码,测试下附件即知,我们利用此方法用UNION选择了1697个单元格都没有报错。
  1. Option Explicit
  2. Sub zz()
  3.     Dim t As Single, rng As Range, arr As Range, StartAdd As String, findstr As String, n As Long
  4.         
  5.     Application.DisplayAlerts = False
  6.     t = Timer
  7.     findstr = "我要的"
  8.     Set rng = ActiveSheet.UsedRange.Find(findstr, LookIn:=xlValues)
  9.     If rng Is Nothing Then Exit Sub
  10.     Set arr = rng
  11.     StartAdd = rng.Address
  12.     n = 1
  13.     Do
  14.         Set arr = Union(arr, rng)
  15.         n = n + 1
  16.         Set rng = ActiveSheet.UsedRange.FindNext(rng)
  17.     Loop While StartAdd <> rng.Address
  18.     arr.Interior.ColorIndex = 46
  19.     Application.DisplayAlerts = True
  20.     MsgBox Timer - t & "秒" & "用UNION共计选定单元格" & n & "个"
  21. End Sub

测试.rar
10楼
wqfzqgk
今天看的好无聊啊,也没事可做,
11楼
bishunbiao
水平有限,只能看懂一部分。看来只能先留下脚印啦。
12楼
luckydog
学习一下
13楼
wangpingqing
马呀,一个上色都这么猛~~
14楼
冰心8549
谢谢分享,学习学习
15楼
老糊涂
收藏学习了
16楼
keven
赞一个!

免责声明

有感于原ExcelTip.Net留存知识的价值及部分知识具有的时间限定性因素, 经与ExcelTip.Net站长Apolloh商议并征得其同意, 现将原属ExcelTip.Net的知识帖采集资料于本站点进行展示, 供有需要的人士查询使用,也慰缅曾经的论坛时代。 所示各个帖子的原作者如对版权有异议, 可与本人沟通提出,或于本站点留言,我们会尽快处理。 在此,感谢ExcelTip.Net站长Apolloh的支持,感谢本站点所有人**绿色风(QQ:79664738)**的支持与奉献,特此鸣谢!
------本人网名**KevinChengCW(QQ:1210618015)**原ExcelTip.Net总版主之一

评论列表
sitemap