在Excel中使用VBA来筛选数据

订购信息:
Excel VBA应用开发从基础到实践 已可从第二书店订购
http://www.cnblogs.com/maweifeng/archive/2006/08/22/483790.html


《Excel与VBA程序设计》最新消息,预计9月上市 

    

1.       问题由来

早晨还没有完全醒来,你就被电话吵醒,有一个中学同学向你请教一个Excel的问题。作为一个所谓的Excel专家,你经常会受到此类骚扰。问题大概是这样的,一个很大的Excel文件,其中有些行是重复的,也就是说,有2行是完全一样的,而有些行是不重复的,现在的问题是要找出所有不重复或者重复的行,你没有听明白。你大概考虑了一下,用“VLOOKUP”查找一下,然后重新排序,应该就可以了,你需要试一下,然后告诉他怎么用,于是你告诉他,20分钟后再打电话给你。

2.       问题解决的思路

你首先打开Excel,输入一些测试数据,大概是这个样子:

 

 

其中“张三”、“李四”有2个,其他只有一个,需要把他们分出来。首先在B列输入1,然后向下填充,在C列输入“VLOOKUP(A1,$A$1:$B$7,2,FALSE)”[①],如果找到,那么返回1,如果找不到,空着就可以了。结果C列全部变成了1 ,因为查找自己肯定可以找到,那么查找的Range必须要去除本行。

你接着找了几个其他函数,“MATCH”,“INDEX”试了试,都无法办到;那么用IF函数呢,你开始试着写IF函数。先输入第4行吧,参数和引用区域回头再处理,或许Excel聪明到可以填充出你需要的引用区域。

你输入了如下的IF函数:

IF(OR(VLOOKUP(A4,A1:B3,2,FALSE),VLOOKUP(A4,A5:B7,2,FALSE)),1,0)

真够复杂的,Excel应该开一个小窗口,然后作为代码输入这样的判断逻辑,IF函数可以嵌套7层,真不知道微软的工程师怎么想的[②],你一边嘟囔一边按下了回车,结果是“#N/A”,就是“值不可用”,你知道函数 VLOOKUP如果找不到需要的值,则返回错误值 #N/A,表达式里有了这个东东,所以不管什么计算,结果都是它了。

       从工具菜单选择“错误检查”,“显示计算步骤”,证实了你的猜测,第二个VLOOKUP函数返回的错误值 #N/A传递到了最后。

 

       这时,你同学的电话来了,你告诉他需要写一段小程序,你决定还是使用直接又简单的VBA来解决问题。

3.       VBA程序

打开VBA编辑器,插入一个模块,你不假思索的敲入了以下代码:

 

Sub SelectDouble()

 

    Dim i As Long, j As Long

   

    For i = 1 To 7 Step 1

        For j = 1 To 7 Step 1

            '不比较相同的行

            If i <> j Then

                If Range("A" & i).Value = Range("A" & j).Value Then

                    Range("E" & i).Value = 1

                End If

            End If

        Next j

    Next i

           

End Sub

 

点击运行,很好,是重复的都标志了1,没有重复的空着,然后排序就可以了。你很满意你还输入了一行注释。你拨通了你同学的电话,告诉他可以了,然后他打电话给你,你把程序念给他,告诉他该改什么地方。天知道他上学时学的什么语言,反正不是Basic,你得解释Dim是什么含义。经过一番折腾,他终于在电话另一端把代码输入了计算机。作为电信员工的他可以每天24小时用电话聊天,只是可怜你的手机话费单,你叹了口气,该去洗脸刷牙了。

4.       效率

洗完脸,刷完牙,你泡好了一杯咖啡,又回到了计算机旁边,电话又来了。你以为是告诉你已经完成了的“喜讯”,听到的却是说死机了,愣了0.1秒钟,你想想应该是程序还在执行或者是死循环。你问了他大概的数据量,知道大概有9000多条记录,还好,你想。

你检查了一下代码,没有什么死循环,也许是你同学输入时有什么错误,你把循环改到1到10000,然后拿起杯子,咽了一口咖啡,往后靠了靠,等着计算结果。几分钟过去了,还是没有结束,你觉得有些奇怪,你敲了“Ctrl + Break”,暂停了程序,将鼠标放在i变量上,显示i还是24,TNND,你知道是Range函数太慢,算了,你打电话告诉你同学,大概需要几个小时才可以计算完成。你又喝了一口咖啡,自言自语道,比起手工筛选,毕竟很快了。

但不就不到1万条纪录吗,Excel的VLOOKUP等内置函数一眨眼也就计算好了啊。

4.1.      通过数组

数组要比Range函数快一些,你把程序改了一下,定义了2个数组,首先把数据全部读入第一个数组,然后对数组进行操作,对于重复的,把第二个数组的相应部分写为1,计算完成后,根据第二个数组,把结果写回去。程序代码如下:

 

Sub SelectDouble2()

 

    Dim i As Long, j As Long

    Dim max As Long

    Dim a() As String, b() As Long

   

    max = 10000

   

    ReDim a(max) As String

    ReDim b(max) As Long

   

    For i = 1 To max Step 1

        a(i) = Range("A" & i).Value

    Next i

   

    For i = 1 To max Step 1

        For j = 1 To max Step 1

            '不比较相同的行

            If i <> j Then

                If a(i) = a(j) Then

                    b(i) = 1

                End If

            End If

        Next j

    Next i

   

    For i = 1 To max Step 1

        Range("F" & i).Value = b(i)

    Next

           

End Sub

 

你执行了一下,对于10000条纪录,大概需要不到5分钟。你觉得很满意,效率提高了几个数量级,你还没有忘记设置了一个max变量,这样,代码使用时改动就会少很多。

4.2.      使用内置函数

你又想起了VLOOKUP这个函数,真是阴魂不散。是啊,为什么VLOOKUP执行这么快,当然是因为它是编译好的,不是用VBA写的[③]。你灵机一动,为什么不用这个函数呢,在VBA中,可以使用Application.函数名,调用Excel的内置函数。这样,改过的代码如下:

 

Sub SelectDouble3()

 

    Dim i As Long, j As Long, a, b

   

    For i = 2 To 9999 Step 1

        a = Application.VLookup(Range("A" & i), Range("A1:B" & (i - 1)), 2, False)

        b = Application.VLookup(Range("A" & i), Range("A" & (i + 1) & ":B1000"), 2, False)

        If IsError(a) And IsError(b) Then

            Range("G" & i).Value = 0

        End If

    Next i

           

End Sub

 

代码很短,但有一点复杂和讨厌,循环是从2到9999,因为为了防止VLOOKUP函数的Range范围失效,所以这两行需要手动处理。IsError函数来检测返回值,如果两个返回值都是错误,则此行为单一的没有重复的行,标志为0即可。程序执行速度和上面的差不多,至少你没有感觉出来差别。

4.3.      继续Hack

到这里,你还是觉得不满意,使用数组,数据量太大会内存吃紧,使用VLOOKUP函数,代码觉得很丑陋[④]。你不知道为什么想起来二分查找之类的东东,那么,查找前应该先排序,你在Excel里把数据排了序。现在的问题是需要循环2次,复杂度为N*N,如果…...,你想如果排好了序,只需要检查当前数值和下一个是否一样,如果一样,那么把当前和下一个位置标示出来,循环变量加2,跳过下一个,如果不一样,循环变量加1继续比较就可以了,代码如下:

 

Sub SelectDouble4()

 

    Dim i As Long, Max As Long

   

    Max = 10000

    i = 1

    Do

        If Range("A" & i).Value = Range("A" & (i + 1)).Value Then

            Range("I" & i).Value = 1

            Range("I" & (i + 1)).Value = 1

            i = i + 2

        Else

            i = i + 1

        End If

    Loop While i < Max

               

End Sub

 

这个程序复杂度只有N,执行速度当然是你今天写的所有程序里最快的,而且内存占用也最小。你觉得很满意,露出了贼贼的笑容。

5.       总结

你打开了日志,开始记下了今天问题的解决过程。

你想,嗯,如果只是想怎样把Range函数变快来解决问题,速度不会有本质的提高。速度提高,第一,排序才是关键,快速的查找和搜索都是要基于排好序的内容,比如二分查找,那么,为什么数据库要建索引,索引的有无对于查找速度影响很大,道理都是一样的了;第二,查找时没有回溯,对于查找过的内容直接跳过,这个和字符串的匹配算法,好像是KMP算法[⑤],思路是一样的,嗯,那么如果不是相同的内容不是2个,是多个,那么你可以使用一个循环来前溯,并且,对于不同的个数,可以标识为不同的数字。你忽然觉得自信满满,似乎要忘了已经失业半年的事实。

 

(2004-11-23 夜)



[①] 在表格或数值数组的首列查找指定的数值,并由此返回表格或数组当前行中指定列处的数值。当比较值位于数据表首列时,可以使用函数 VLOOKUP 代替函数 HLOOKUP。具体用法可以参考Excel帮助。

[②] 作为程序员的你,一直觉得IF函数之类是浪费时间和多此一举,7层的IF函数怎么看得懂?但函数代表简单,你不想因为告诉你同学要写程序解决问题而把他吓坏。

[③] 天知道微软用什么写的这些代码,也许是C,也许是C++,肯定不是Basic,也不是C#,写它时C#还没有出生呢。

[④]或许是你没有写好。

[⑤] 虽然不是科班出身,你也学过数据结构和算法的。

posted on 2004-12-01 13:55 马维峰 阅读(58719) 评论(212) 编辑 收藏

评论

#142楼 2006-06-03 07:51 sunny-fine![未注册用户]

马老师,您好!
我在一本vb教程上看到说excel控件箱里有个"计时器-timer",能够被用来做简单的动画,可是我的excel控件箱里怎么没有这个控件那?
thank u!
 回复 引用   

#143楼[楼主] 2006-06-03 11:24 马维峰      

@sunny-fine!
只能说这本书胡说了,呵呵。VB中有这个控件,VBA的Form或者工作表的控件工具箱中是没有这个控件的。

可以使用Application对象的Timer属性。可以参考Excel VBA一书的Excel对象模型一章。
 回复 引用 查看   

#144楼 2006-06-05 07:39 sunny-fine![未注册用户]

马哥:
您好,现在我想把excel中符合条件的几行数据(比如说5行3列)从一个用户窗口中显示出来,而且行列位置不变,请问这能否实现在vba中。
谢谢指教,祝天天开心!
 回复 引用   

#145楼[楼主] 2006-06-05 12:42 马维峰      

@sunny-fine!
可以,使用用户窗体,显示数据可以使用Grid控件(需要增加到控件工具箱),或者使用多个文本框模拟。

 回复 引用 查看   

#146楼 2006-06-05 15:58 sunny-fine![未注册用户]

马哥,谢谢您的回复,不过我真的不清楚什么是grid控件,如果是很复杂的,我就选用后一个方法。
后面的方法中,假设用户窗体中文本框的名字叫aa,我要输入"hello the worlld", 看完您的书后,我这样写了:
sub 确定click()
open aa for output as #1
write #1,"hello the world"
end sub
可是,怎么都显示有错误,请指教!

 回复 引用   

#147楼[楼主] 2006-06-05 16:27 马维峰      

@sunny-fine!
这个方法是读文件啊?
使用控件请参考VBA语言的窗体编程一节。
 回复 引用 查看   

#148楼 2006-06-10 12:22 uu[未注册用户]

马老师,
我想新建一个工作簿,然后给它命名,
sub 55()
worksheets.add
newsheet.name="00"
end sub
这个第三行应该怎么表达,谢谢了!
 回复 引用   

#149楼[楼主] 2006-06-10 16:32 马维峰      

@uu
可以参考Excel VBA一书的“对象模型”一章有关内容,有示例。
http://maweifeng.cnblogs.com/archive/2006/03/31/363176.html
 回复 引用 查看   

#150楼 2006-06-12 12:55 uu[未注册用户]

马老师,您好!
vba中的并列循环结构怎么编写,您能帮我举个例子吗?
 回复 引用   

#151楼[楼主] 2006-06-12 13:41 马维峰      

@uu
什么是并列循环结构?
 回复 引用 查看   

#152楼 2006-06-12 18:05 uu[未注册用户]

马老师,不好意思,这个名词是我自己创造的,这个问题我明白了现在,原来我以为两个for 循环中只能是后面的嵌在前面的,原来也可以并列使用,不过同样谢谢您,一直在看您的书学着编程。  回复 引用   

#153楼 2006-06-14 11:47 spie@163.com[未注册用户]

你的这个问题,用下面函数一下搞定了,用得着这么复杂吗?
=COUNTIF(I3:I11,I3)

比如查找I3在I3:I11中出现的次数,一次就是只有一个,1个以上就是有重复的了。

希望能复杂事情简单化而不是更复杂。
 回复 引用   

#154楼 2006-06-14 17:57 uu[未注册用户]

马老师,您好!
还有一个问题要请教:
我想在每次关闭excel(文件时弹出来一个对话框,提醒要删除一个临时用的sheet,怎么实现?
根据您的excel一书,我已经写出了这些:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
MsgBox "有一个临时的sheet需要删除"
End Sub
我已经把它放到了一个类模块里,但 withevents 怎么使用,我还是没看明白,请您指教.
十分感谢!
 回复 引用   

#155楼[楼主] 2006-06-14 22:58 马维峰      

@uu
在ThisWorkbook模块内选择BeforeClose事件,写这个过程。
 回复 引用 查看   

#156楼 2006-06-15 09:25 sunny-fine![未注册用户]

马老师,问题解决了,谢谢您的回复,祝顺利!  回复 引用   

#157楼 2006-06-17 09:53 Poloar[未注册用户]

@SUMMER
是不是要打印票据
搜索一下
我在网上看到过
 回复 引用   

#158楼 2006-06-25 10:33 sunny-fine![未注册用户]

马老师,您好!
在您的帮助下,我已经顺利的完成了一个excle宏的设计,并派上了用场,发挥了很大的作用在实际工作中。
现在我还有一个问题,就是如何保护我的vba代码,以避免别人的浏览和改动。
再次深表感谢!
 回复 引用   

#159楼[楼主] 2006-06-26 12:56 马维峰      

@sunny-fine!
可以在VBA环境下选择 工具 - [VBAProject]选项 - 保护,
添加密码,并选择锁定工程。
 回复 引用 查看   

#160楼 2006-06-26 16:22 sunny-fine![未注册用户]

谢谢您,马老师,您教的方法就是简单、实用  回复 引用   

#161楼 2006-06-27 21:28 张先生[未注册用户]

马老师:
你好!
我对你在EXECEL表中筛选同情的程序非常的赞赏,而且帮了我很大的忙,现在我又出现了一个非常复杂的问题比如说下边的表格:
D32057FN TI 2
D72008UFNL TI 2
D72028UFNL TI 11
D62053FN TI 10
D12089FN TI 10
D14003FN TI 22
D14006FN TI 100
D32054FNL TI 10
D32053FNL TI 7
D32051FNL TI 1000
能不能写个程序把第一列相同的型号找出来并且把第三列相同的型号的数量给相加起来。然而并不是再第四列把相同的型号打上1 ,这样对于比较大的数据库,又想把相同的给去掉,做起来就很麻烦。所以想请你帮忙写个程序,把第一列相同的找出来。并把第三列相同型号的数量累加,有必要的话我想加你QQ私聊可以吗?

希望得到你迅速的回复
 回复 引用   

#162楼 2006-06-28 11:46 sunny--fine[未注册用户]

马老师,您好!
我编的代码中有这么一段,用来判断excel某一列中有多少条连续的非空数据,首先我把sheet 2 重新命名为“操作台”:
for i = 1 to 1000 step 1
if worksheets("操作台").cells(i,1)="" then
p=i-1
msgbox p
exit for
end if
next i

程序在运行时偶尔出现调试的窗口,说 if worksheets("操作台").cells(i,1)="" then 这行数据类型不匹配,我把它写成 if worksheets(2).cells(i,1)="" then 就可以继续运行了,请问这是怎么回事?
麻烦您了!


 回复 引用   

#163楼[楼主] 2006-06-28 15:11 马维峰      

@sunny--fine
出现“数据类型不匹配”应该是因为某些单元格的数值类型的问题吧?使用worksheets("操作台")和worksheets(2)是没有差别的。
 回复 引用 查看   

#164楼[楼主] 2006-06-28 15:17 马维峰      

@张先生
可以使用IF函数判断,也可以参照本例编程实现。
 回复 引用 查看   

#165楼 2006-06-28 15:55 张先生[未注册用户]

马老师
你好!
那我可不可把我的样本发给你,然后你在帮找出具体的方法可以吗?

谢谢
 回复 引用   

#166楼 2006-06-30 12:09 dany11111[未注册用户]

马老师,您好!
我想问一下,如何判断一个表的名称是否存在?
 回复 引用   

#167楼 2006-06-30 16:33 F9[未注册用户]

你也太麻烦了吧!一个简单的问题尽然让你给搞成这样,还要VBA,恐怖!
其实你第一个方法就可以解决,最多应该五分钟就可以搞掂了!把公式换一下:
=IF(ISNA(VLOOKUP(a1,a2:$b$10000,2,FALSE)),"0",VLOOKUP(a1,a2:$b$10000,2,FALSE)),
拖到10000,然后筛选出“0”来删除,ok!!
 回复 引用   

#168楼 2006-06-30 21:18 analyse excel[未注册用户]

马老师,您好!我想请教您怎么才能EXCEL中实现以下功能,谢谢!
如果有一个长方形长*宽为:1000*2000,现有一个小长方形为X*Y(X,Y满足以下条件:X<1000 AND Y<2000 或X<2000 AND Y<1000)(只要X,Y满足以上条件就才可进行运算),,怎么才能算出1000*2000这个长方形最多可由多少个X*Y的小长方形组成。例如:1000*2000长方形最多可由1个1000*2000长方形组成,最多可由2个990*990长方形组成(余下部分不计,必须要能放下整个小长方形X*Y才能算一个),等等,急用,谢谢!
 回复 引用   

#169楼 2006-06-30 21:24 analyse excel[未注册用户]

马老师,关于锁定EXCEL中的宏不被别人访问和修改的问题.我听同事说,在"VBA环境下选择 工具 - [VBAProject]选项 - 保护,
添加密码,并选择锁定工程"这个办法,现在在网上有很多的解密软件可以轻松破解,有没有更好的办法?谢谢!
 回复 引用   

#170楼[楼主] 2006-07-01 12:02 马维峰      

@analyse excel
这个问题没有那么严重,密码设置长一些。
如果不想让破解,选择把一些模块放入DLL中,在VBA中调用也是一个办法,或者设计一个COM加载宏。
 回复 引用 查看   

#171楼[楼主] 2006-07-01 14:43 马维峰      

@dany11111
可以使用类似下面的代码:
for each w in worksheets
if w.name = "..." then
bFind = true
end if
next


 回复 引用 查看   

#172楼 2006-07-02 01:10 analyse excel[未注册用户]

马老师,您好!我想请教您怎么才能EXCEL中实现以下功能,谢谢!
如果有一个长方形长*宽为:1000*2000,现有一个小长方形为X*Y(X,Y满足以下条件:X<1000 AND Y<2000 或X<2000 AND Y<1000)(只要X,Y满足以上条件就才可进行运算),,怎么才能算出1000*2000这个长方形最多可由多少个X*Y的小长方形组成。例如:1000*2000长方形最多可由1个1000*2000长方形组成,最多可由2个990*990长方形组成(余下部分不计,必须要能放下整个小长方形X*Y才能算一个),等等,急用,谢谢!
 回复 引用   

#173楼[楼主] 2006-07-02 16:49 马维峰      

@analyse excel
你还是找本算法的书参考参考吧,这个问题应该在很多书的习题里都有。
 回复 引用 查看   

#174楼 2006-07-02 19:51 sunny-fine.[未注册用户]

Sub trcl()
b = InputBox(请输入单元格范围) 输入的内容比如是: e2:e5
x = Left(b, 1)
y = Val(Mid(b, 2, 1))
Range("x&y").Activate
end sub

运行时对话框说方法’range‘作用于对象‘—global’时失败,请问马老师这是怎么回事?
谢谢您!
 回复 引用   

#175楼[楼主] 2006-07-02 20:21 马维峰      

@sunny-fine.
Range(x&y).Activate, 去掉引号,因为x,y已经是字符串。

这个问题,也建一个用户窗体,使用引用控件来得到单元格引用。
 回复 引用 查看   

#176楼 2006-07-03 09:21 dany11111[未注册用户]

谢谢 马老师我的问已解决,这是您的代码写的
For Each w In Worksheets
If w.Name = "统计结果" Then
Sheets("统计结果").Delete
End If
Next
这是我的代码写的,不知合适否?
On Error Resume Next
If Sheets("统计结果").Visible Then Sheets("统计结果").Delete
 回复 引用   

#177楼[楼主] 2006-07-03 12:31 马维峰      

@dany11111
2种方法都可以。
 回复 引用 查看   

#178楼 2006-07-03 18:22 sunny-fine.[未注册用户]

Sub trcl()
b = InputBox(请输入单元格范围) 输入的内容比如是: e2:e5
Range(" ").Activate
end sub

我想使输入列的下一列的同行单元格"f2"处于激活状态,在空白处怎么表达?因为输入是随机的,所以我不会了这下,劳驾您指教!
 回复 引用   

#179楼[楼主] 2006-07-03 23:21 马维峰      

@sunny-fine.
Range(b).Cells(1, 2)
 回复 引用 查看   

#180楼 2006-07-04 22:30 analyse excel[未注册用户]

马老师,那个关于长方形的问题我已解决了,谢谢您!其实是个很简单的问题,以前学的都忘了,赶紧复习才行,谢谢您的指导。  回复 引用   

#181楼 2006-07-05 10:01 fengzy[未注册用户]

马老师你好!
请教个问题:
dim s as string,yzname as string
dim pos1 as double
yzname=worksheets(1).cell(i,6).value
For k = 1 To 68
s = Worksheets(3).Cells(1, k).Value
pos1 = Application.WorksheetFunction.Find(s, yzname)

If pos1 〉0Then curcol = k
Exit For
Next k
s,yzname 均是中文字符串,此窜程序要求在第一行中查找是否有包含在yzname中的单元格存在
运行时报错:“不能取得workfunction的find属性” ?
 回复 引用   

#182楼[楼主] 2006-07-06 12:43 马维峰      

@fengzy
可以使用VBA函数,例如Instr等等。
 回复 引用 查看   

#183楼 2006-07-06 16:00 晨曦[未注册用户]

马老师您好:
这个问题困绕了我一天了,还没解决,用COUNTIF能实现吧,比如,A1:A8 满足等于1的条件同时C1:C8也得满足a的条件,请问公式应该怎么写?谢谢了,希望能传到我的QQ里或者邮箱,chenxihg@126.com
 回复 引用   

#184楼 2006-07-06 16:07 晨曦[未注册用户]

马老师,您好,又打扰您了,顺便把我的QQ告诉您,以便能以后更好的向您请教,谢谢了  回复 引用   

#185楼 2006-07-06 16:08 晨曦[未注册用户]

QQ346156653  回复 引用   

#186楼 2006-07-06 21:22 sunny-fine.[未注册用户]

Sub 宏2()
Dim x As String

x = InputBox(请输入单元格的范围:)
Range(x).Cells(1, 2).Activate
ActiveCell.FormulaR1C1 = "=COUNTIF(range(x),RC[-1])"

End Sub

马老师,上面的 "=COUNTIF(range(x),RC[-1])" 中 range(x) 怎样表达才是对其单元格范围的绝对引用那,在countif 这个公式里。
多谢您一直以来的帮助,祝天天开心!

 回复 引用   

#187楼 2006-07-07 10:12 晨曦[未注册用户]

马老师,不好意思又来打扰你了,我对EXCLE的函数应用真的是不怎么太懂,只会些简单的,更不要说"宏"了,您上面说的也许是宏,但我没看明白,我编辑了一个公式但不对,您给指导指导, 也许是我没说明白,比如工作薄里A1:A10单元格内若等于1,B1:B10同时的单元格等于a的时候,符合这两个条件的的单元格的个数,计数自动在C6单元格内显示,请问C6单元格内的函数公式应该是什么?我自己编写了一个,但不对,您给修正修正
=countif(a1:a10,"1")-countif(b1:b10,"a")但中间连接好象不对,麻烦您了~!
QQ346156653
 回复 引用   

#188楼[楼主] 2006-07-07 10:44 马维峰      

@sunny-fine.
使用Address可以获得绝对引用的地址。
@晨曦
函数使用应该有帮助,你查一下。每个公式都有相应的说明。
 回复 引用 查看   

#189楼 2006-07-07 11:06 晨曦[未注册用户]

马老师您好,我找了,可是符合两个条件的确实没有,单个条件的我会弄,两个条件的就不知道了  回复 引用   

#190楼 2006-07-07 11:09 晨曦[未注册用户]

要不您加我QQ我把原文件发给您得了,这样好参考  回复 引用   

#191楼 2006-07-08 19:39 sunny-fine [未注册用户]

Sub 宏2()
Dim x As String
x = InputBox(请输入单元格的范围:)
Range(x).Cells(1, 2).Activate
ActiveCell.FormulaR1C1 = "=COUNTIF(range(x),RC[-1])"
End Sub

马老师,按照您给的建议我试着这样写了ActiveCell.FormulaR1C1 = "=COUNTIF(address(x),RC[-1])",可是没有搞定,我怀疑在第5行的 "=COUNTIF(range(x),RC[-1])" 中的 x 是不是不可以和第3行中的 x 进行代换,那么我要想使这个 x 随着第三行的随机输入而变化应该怎么办(且是绝对引用的形式)。
麻烦您了!
 回复 引用   

#192楼[楼主] 2006-07-08 21:12 马维峰      

@sunny-fine
这一行:
ActiveCell.FormulaR1C1 = "=COUNTIF(range(x),RC[-1])"
简单一些,可以写作:
ActiveCell.value = "=COUNTIF(x,RC[-1])"
 回复 引用 查看   

#193楼 2006-07-09 09:59 sunny-fine.[未注册用户]


马老师,您好,这个方法我试了,在执行“x = InputBox(请输入单元格的范围:)”语句时我输入的是b2:b9,运行完毕后,在activecell里的公式显示的依然是 =COUNTIF(x,B2),看样子,这个 x 没有办法和前面的进行代换了。既然不能对countif公式里的x进行精确控制,我又这样写了:ActiveCell.FormulaR1C1 = "=COUNTIF(R1C[-1]:R30000C[-1],RC[-1])",行数从1到30000一般足够了在实际中,而列设定为相对引用,但不影响列的向下自动填充。
后面的办法已在我的机器进行了测试,比较成功,thank u all the same!
 回复 引用   

#194楼 2006-07-10 17:40 bluemoodiness[未注册用户]

马老师你好,我想将下面的数据中第二列中,凡是中文字相同的都筛选出来,复制到另外一个sheet.可以实现吗?请指导下,谢谢!
2006-6-1 高低村9
2006-6-2 仁寿山1
2006-6-3 仁寿山2
2006-6-4 仁寿山3
2006-6-5 仁寿山2
2006-6-6 塘溪2
2006-6-7 塘溪2
2006-6-8 高低村M9
2006-6-9 市府1
2006-6-10 市府2
2006-6-11 市府3
2006-6-12 市府2
2006-6-13 市府1
2006-6-14 市府2
2006-6-15 小岛2
2006-6-16 小岛2
2006-6-17 芙冈3
2006-6-18 芙冈3
2006-6-19 立圆3
2006-6-20 网地1
2006-6-21 网地2
2006-6-22 网地3
2006-6-23 立圆3
2006-6-24 发电厂2
2006-6-25 网地1
2006-6-26 东向1
2006-6-27 网地3
2006-6-28 东向2
2006-6-29 网地2
2006-6-30 东向3
 回复 引用   

#195楼[楼主] 2006-07-11 01:10 马维峰      

@bluemoodiness
这个应该可以使用公式实现。
例如VLOOKUP。
 回复 引用 查看   

#196楼 2006-07-12 22:10 analyse excel[未注册用户]

马老师,我遇到这样一个问题,请您帮我看看,谢谢!
问题是:
如果.CELLS(1,1)满足条件A,则.CELLS(2,1)=B;如果.CELLS(3,1)满足条件C,则.CELLS(3,1)=.CELLS(3,1)*.CELLS(2,1),但我想要只要当.CELLS(3,1)满足条件后只运行一次,可以吗?请在我发给您的表格时输入少于100的数,点击.CELLS(2,1),谢谢!您的学生.
 回复 引用   

#197楼 2006-07-13 13:07 sunny-fine[未注册用户]

马老师,您好!
还有两个问题向您请教:
1、我现在在excel里自定义了一个工具栏,主要是用来清除单元格里的多余空格,在打开其他excel文件时,这个工具栏一样可以出现在其他工具栏的后面,但是在使用它的时候,有时会出现类似“无法打开某某文件的宏”的字样,或者能执行但同时弹出来一个附属的工作簿,不知道应该怎样解决这个问题,就是最好能使这个工具栏能对我机器里的所有excel文件普遍适用。
2、我需要在word里实现金额的大小写的转换,我这样编了:
sub zhuanhuan()
dim i as integer
i=5,556
p=application.text(i,"[DBNUM2]G/通用格式")
msgbox p
end sub
在执行时,代码的第四行有问题,我想知道应该怎么修改。
两个问题再次麻烦您,深表感谢!
 回复 引用   

#198楼[楼主] 2006-07-14 21:54 马维峰      

@sunny-fine
第一个,设计为一个加载宏试试。
第二个,没有怎么使用过word的VBA,(1)text的函数使用是否正确;(2)这个函数能否在VBA中使用。
 回复 引用 查看   

#199楼 2006-07-15 11:59 supperST[未注册用户]

'有疑问请教:
Sub 删除多余重复数据2() '整行

Dim su As Variant
Dim a As Long
Dim b As Long

a = [c65530].End(xlUp).Row
b = 0 '如果将 b = b - 1语句 放在Delete前面则应设为b=1
'赋值从C1开始,因为要保持单元格行号和数组行号一致
su = Range([c1], Cells(a, 3)) ' 将值转到数组

For i = 3 To a '首两行是标题行,所以从3开始查
'我的疑问在此:
'下行的Range("C:C")上,为什么不可以换成数组范围的形式?即换成su
If Application.CountIf(Range("C:C"), su(i, 1)) > 1 Then '查C列

Cells(i + b, 3).EntireRow.Delete
b = b - 1 '因为删除了一行所以要-1查回此行
End If

Next i


End Sub
 回复 引用   

#200楼 2006-07-15 15:46 supperST[未注册用户]

马老师你好:

通过循环运算,变量a被赋值,而且是个超长的文本,2千至3千字

问题:如何把a值复制到粘贴板上?便于我粘贴到其它程序上面。

( 如果将a赋值给单元格,再copy单元格,只能复制到头256个字符的文字,无法复制到全部!!)
 
 回复 引用   

#201楼[楼主] 2006-07-16 00:22 马维峰      

@supperST
Range("C:C")表示整行。
 回复 引用 查看   

#202楼[楼主] 2006-07-16 00:25 马维峰      

@supperST
Dim MyData as DataObject
MyData.SetText( range("a1").value)
 回复 引用 查看   

#203楼 2006-07-22 00:32 supperST [未注册用户]

Sub dfdf()
Dim MyData As DataObject
MyData.SetText (Range("a1").Value)
End Sub

提示用户定义类型未定义?
 回复 引用   

#204楼[楼主] 2006-07-22 01:09 马维峰      

@supperST
DataObject需要在窗体中定义。如果在其他地方使用,可以增加一个窗体,定义这个对象为Public,然后使用。

Dim MyData As New DataObject
MyData.SetText CStr(Range("a1").Value)
MyData.PutInClipboard
 回复 引用 查看   

#205楼 2006-07-22 10:49 supperST [未注册用户]

初步测试OK,很感谢!

还有个问题困扰很久了:
excel导出txt文件后,我用shell方法打开其它程序,那个其实是查询程序,每次是重复的操作动作导入那个txt文件进行批量查询,我希望一步到位……

但那个程序没有快捷键,无法用sendkeys的方法控制按键;唯有曲线救国——控制鼠标动作,我用过按键精灵,它的控制动作就是用VBS和键盘语做的,我能用它来定位屏幕鼠标位置,但不知在VBA里用什么方法控制??

希望在VBA实现:
1、鼠标移动到指定屏幕坐标
2、左键单击
3、左键双击
4、延时控制


提供按键精灵部分脚本参考:

#这是按键精灵生成的脚本源文件
#在理解各条命令的基础上,您可以修改这个文件的内容
#您修改的结果将会在普通视图上有所反映

KeyDown 17 1
KeyPress 65 1
MoveTo 269 672
LeftClick 1
KeyPress 65 1
MoveTo 269 672
LeftClick 1
KeyPress 65 1
MoveTo 269 672
LeftClick 1
 回复 引用   

#206楼[楼主] 2006-07-22 11:32 马维峰      

@supperST
VBA下可以调用VBS脚本,使用Script控件。
 回复 引用 查看   

#207楼 2006-07-22 13:30 supperST [未注册用户]

@马维峰
马老师:
能说具体点吗?我看过帮助没看懂

“使用Script控件。”是不是在“引用”里选,如果是要选哪项?
希望在VBA实现:
1、鼠标移动到指定屏幕坐标
2、左键单击
3、左键双击
4、延时控制
 回复 引用   

#208楼 2006-07-28 22:24 analyse excel[未注册用户]

马老师:
您好!
请问怎么样在EXCEL中将数据(包括小数在内)转换成大写字母(我也是用于会计上的)?我在上面看到一个叫SUMMER的朋友问了这个问题,但是没有看到具体的回复,请您帮我解决这个难题,谢谢!
 回复 引用   

#209楼 2006-07-31 11:54 sunny-fine[未注册用户]

马老师,您好,

sub 输出()
e=36803.77*100
i=int(e)
msgbox i
end sub

输出的对话框中 i 的值应该是3680377才对,可是不知道为什么却是3680376,我实验了好几遍,不知道为什么,请教马哥给解答一下。
 回复 引用   

#210楼 2006-07-31 12:12 sunny-fine[未注册用户]

sub 输出()
e=36803.77*100
i=int(e)
msgbox i
end sub

正常输出的 i 的值应该是3680377才对,而实际输出的却是3680376,不知道为什么,请教马老师给指点一下,困扰了一个上午被这个问题。
 回复 引用   

#211楼 2006-08-08 10:51 retifax[未注册用户]

这篇文章里的最后一段代码,以2为步进,如果有单数个重复的,就会有一个查不出来,不是么,另外我想请问一下马老师,在VBA中,有什么函数能够读取Excel单元格公式的值呢?  回复 引用   

#212楼 2006-08-15 18:57 li junfeng[未注册用户]

马老师:
您好!
Sub Form_Load()
Dim xl As New Excel.Application, sht As New Worksheet
Dim s As String
Dim x As Integer, y As Integer '插图时的左上角坐标
Const sPath = "C:\Picture\"
Const nWidth = 100, nStep = 10 '每张图的长宽和贴图间距,随 需要调整

Set sht = xl.Workbooks.Add.Sheets(1)
sht.Cells(1, 1).Select
x = 0: y = 0

使 * 变成变量 引用如(A1:A10)在WORKBOOK。SHEETS(1。 EXCEL 文件!这样可以通过 A1:A10 来显示不同的图片。而A1:A10是我想要显示的图片。

s = Dir(sPath & "*.jpg")
While s <> ""
sht.Pictures.insert(sPath & s).Select
With xl.Selection.ShapeRange
.LockAspectRatio = False
.Width = nWidth
.Height = nWidth
.IncrementLeft x * (nWidth + nStep)
.IncrementTop y * (nWidth + nStep)
x = x + 1
If x >= 6 Then '每行贴10张,换行再贴
x = 0: y = y + 1
End If
End With
s = Dir() '继续下一个
Wend

xl.Visible = True
Set xl = Nothing
Set sht = Nothing
End Sub
 
 回复 引用   

#213楼 2006-09-12 11:14 chris[匿名][未注册用户]

我想问一下,如何把所有sheet的名称筛选出来  回复 引用   

#214楼[楼主] 2006-09-12 20:54 马维峰      

使用Worksheets集合  回复 引用 查看   

#215楼 2006-09-14 20:12 sunny-fine[未注册用户]

马老师,您好!
在excel中,A1到A3中分别为:
gh uu hh A001
ghb ii hh 0033C
ghcc ww ii 00225
其中我想把最后一个空格后面的字符给提出来,也就是要分别得到:
A001
0033C
00225
但这些字符的个数和空格前面的字符个数都是不确定的,怎么实现那?
谢谢指导!
 回复 引用   

#216楼[楼主] 2006-09-14 21:12 马维峰      

@sunny-fine
使用VBA的Split函数,分割为字符串数组。
 回复 引用 查看   

#217楼 2006-09-26 11:06 小小[匿名][未注册用户]

请教!我做了一个统计表,每天都在加数据,但我怎样能实现比如N天的平均数呢?如,最近3天,最近5天?请指点  回复 引用   

#218楼 2006-10-02 10:48 sunny-fine.[未注册用户]

马老师的新书我已买到了,正在系统的研读那,设计也很精美,在书架上也比较focus  回复 引用   

#219楼 2006-10-03 17:26 高江川[未注册用户]

马老师 你好 !
我是第一次登陆您的网站 感觉您的电脑操作知识十分丰富
希望能请教您一个问题
请问如何在Excel中输入角度 如果将角度推算为弧度是可以不影响计算结果 但对于测量结果来说是个变动 希望马老师在看过这个问题后能给我恢复!我的邮箱是gough152502@163.com
 回复 引用   

#220楼[楼主] 2006-10-03 18:43 马维峰      

@sunny-fine.
谢谢你的支持。
 回复 引用 查看   

#221楼[楼主] 2006-10-03 18:44 马维峰      

@高江川
计算结果影响与否应该看计算的需求,精度要求吧?
 回复 引用 查看   

#222楼 2006-10-04 15:51 sunny-fine[未注册用户]

在上面的问题中,您告诉我用 split 函数,我新建了一个function,比较好用,可是现在我想写一段vba程序,
sub split()
dim words() as string
aa = "ghcc ww ii 00225"
words() = split(aa)
msgbox words(2)
end sub
运行后,我认为msgbox应该显示出“ii”,可是没有成功,不知道问题出在那里了。
顺祝马老师十一快乐!
 回复 引用   

#223楼[楼主] 2006-10-05 11:18 马维峰      

@sunny-fine
words() = split(aa) 应该是:
words() = split(aa, " ")
缺省分隔符应该是逗号,使用其他分隔符要指定。
 回复 引用 查看   

#224楼 2006-10-15 19:24 sunny-fine[未注册用户]

马老师,谢谢您的指导,现在我还想知道比如在"ghcc ww ii 00225" 中含有4个元素,这个值在excel 中有没有现成的公式可以来进行统计?
祝您愉快!
 回复 引用   

#225楼 2006-10-30 16:47 zhangdaming[未注册用户]

执行以下代码我发现系统不断重复的执行此代码,有什么办法即能改变其他单元格的值而不引起死循环呢?我已经郁闷好几天了,大哥帮忙啊!!!
我的邮箱 single666@163.com

Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Range("a1").Value = "123"
MsgBox "a1的值已经改变"

End Sub
 回复 引用   

#226楼 2006-11-16 23:16 小钟[未注册用户]

马老师,想请教你,我有个EXCEL表中有A和B二组电话号码5000多个,A里面有C,B里面也有C,要先选出A和B里面的C,再把A里面的C删除,C的数量可能有一百多个,能不能帮我写个小程序.谢谢!  回复 引用   

#227楼 2006-11-16 23:26 小钟[未注册用户]

马老师,想请教您,我有个EXCEL表中有A和B二组电话号码5000多个,A里面有C,B里面也有C,要先选出A和B里面的C,再把A里面的C删除,C的数量可能有一百多个,能不能帮我写个小程序.非常谢谢!我的邮箱是:maichcal@sina.com.cn  回复 引用   

#228楼 2006-12-09 15:01 luffy.deng[未注册用户]

对于这样的问题为什么不用高级筛选?  回复 引用   

#229楼 2006-12-28 12:48 Wilson[未注册用户]

@nolen
用countif 就行
 回复 引用   

#230楼 2007-01-19 14:55 小莫[未注册用户]

马老师,您好,一直都在您的博客上学习,工作了,终于有了问题,现在想浮水请教您!我手中有一批学生本学期的期末考试成绩,我都汇总了,现在想把成绩不及格的筛选出来,复制去另外一个新建表格,请问那个命令如何使用!谢谢您!我的油箱是 nikemsy1109@163.com  回复 引用   

#231楼 2007-02-28 14:19 杨[未注册用户]

马老师,你好,怎样输入度分秒呀,我是一个测量专业的学生,遇到一些小的计算觉得通过EXCEL计算很方便。但是,找了半天就是不知道怎样通过这个软件输入度分秒,并且还要他们进行计算!013859509123  回复 引用   

#232楼 2007-02-28 14:20 杨[未注册用户]

马老师,你好,怎样输入度分秒呀,我是一个测量专业的学生,遇到一些小的计算觉得通过EXCEL计算很方便。但是,找了半天就是不知道怎样通过这个软件输入度分秒,并且还要他们进行计算!013859509123
longyan@southsurvey.com
 回复 引用   

#233楼 2007-04-03 11:11 刘燕[未注册用户]

老师您好!这些内容我怎么觉着这么高深呀。
我有一简单问题:在EXCEL表格中B列我输入了好多村名,同时在C列输入的是这些村里的用户姓名(每个村里用户都不一样多,并且村名也不是按顺序来的),我想统计一下某个村有多少个用户,怎么统计呀?急盼答复。
 回复 引用   

#234楼 2007-04-29 12:02 草[未注册用户]

如果不写程序

在B列输入序列值1,2,3...,而不是全为1
在C列使用vlookup,则返回搜索到的第一个值,即重复相返回的是相同的值,这时b列和c列就会出现不同的值,
在D列计算b和c的差值,不为零的相即为需删除的重复相,排序后删除即可

张三 1 1 0
里斯 2 2 0
张三 3 1 2
里斯 4 2 2
王五 5 5 0
大麻子 6 6 0
小七 7 7 0
 回复 引用   

#235楼 2007-09-16 15:50 xchxch[未注册用户]


我认为筛选数据还是用数组比较快,上面数组的赋值
For i = 1 To max Step 1

Range("F" & i).Value = b(i)

Next

应直接赋值,range("f1:f10000") = b(1 to 10000)
 回复 引用   

#236楼 2007-11-24 12:42 王宝林[未注册用户]

你好
我想请教您一个问题:怎么在vb中找出excel中一列大于10的数值并且对其求和值
谢谢
 回复 引用   

#237楼 2007-11-28 17:39 果皮[未注册用户]

这个方法好,呵呵@huxinjie
 回复 引用   

#238楼 2008-06-05 15:47 路过[未注册用户]

有COUNTIF就能实现,搞这么复杂  回复 引用   

#239楼 2008-10-25 09:33 李林2[未注册用户]

你好,我想请教一个问题,我是一个初学者,我想把EXCEL一个列里的全部数据里查找出其中的我需要的数,除了查找以外,还有没有更简捷的方法,如一个列里有4000个数,各种数是不同的,我要在其中一下子查找出我需要的数据,怎么查找?谢谢!  回复 引用   

#240楼 2011-05-13 21:15 geminik      

你好,咨询一下,使用该方法来筛选重复数据,但如何每个重复数字出现的次数呢,这个暂时没有思路,谢谢  回复 引用 查看   

#241楼 2011-11-29 09:40 伍华聪      

关于Excel等相关文件的操作,我的共用类库也提供丰富的操作。

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(4)
http://www.cnblogs.com/wuhuacong/archive/2011/07/30/2121829.html

1、CSV文件和DataTable对象转换辅助类 CSVHelper
2、 Excel操作辅助类(无需VBA引用) ExcelHelper
.....
6、 INI文件操作辅助类 INIFileUtil
 回复 引用 查看   

评论共3页: 上一页 1 2 3 

公告

昵称:马维峰
园龄:7年2个月
粉丝:45
关注:0

统计

  • 随笔 - 345
  • 文章 - 24
  • 评论 - 1665

搜索

 

常用链接

我的标签

随笔分类(437)

随笔档案(350)

文章分类(34)

文章档案(24)

GIS站点

个人链接

积分与排名

最新评论

阅读排行榜

评论排行榜

推荐排行榜