是否有一个像VBA函数HasFormula一样的IsNumeric范围版本?

7

我知道range().HasFormula只有当范围中的每个单元格都是公式时才返回True,否则可能返回False或Null(混合情况)。但是没有像HasNumber这样的函数。因此,要检查一个范围是否只包含数字,我必须执行以下操作:

Dim all_numeric As Boolean
all_numeric = True
For Each cell In Range()
    If (Not IsNumeric(cell)) Or IsEmpty(cell) Then 'I also want to get rid of empty cell
        all_numeric = False
        Exit For
    End If
Next cell

另外,还有WorksheetFunction.IsNumber可以完成类似的任务,但仍然需要循环遍历整个范围。如果范围包含大量数字,这可能会非常缓慢。我想知道是否有更好的方法在VBA中检查范围对象上的数值。


3
也许 all_numeric = (r.Cells.Count - Application.Count(r)) = 0(其中 r 是一个 Range 对象)意味着所有单元格都是数字。 - YowE3K
@YowE3K 好的,很棒! - Nicholas
这正是[codereview.se]最擅长的。我实际上会包括函数的签名/整个主体;如果它只是更大过程的一部分,我会包括整个过程。如果该过程使用模块级变量,我会包括整个模块。 - Mathieu Guindon
1个回答

10

也许 all_numeric = (r.Cells.Count - Application.Count(r)) = 0 (其中 r 是一个 Range 对象)? – YowE3K 35 分钟前

这确实很优美: 它利用了Excel自己的返回范围内数字值数量的函数来确定结果:

WorksheetFunction.Count

计算包含数字的单元格数并计算参数列表中的数字。

https://msdn.microsoft.com/zh-cn/library/office/ff840324.aspx

错误单元格和空单元格不计入统计,这满足了您不计算空单元格的要求。
这是一个很好的用户定义函数(UDF),可以在标准模块中公开使用。
'@Description("Returns True if all cells in specified range have a numeric value.")
Public Function IsAllNumeric(ByVal target As Range) As Boolean
    IsAllNumeric = target.Cells.Count - Application.WorksheetFunction.Count(target) = 0
End Function

请注意,我使用的是Application.WorksheetFunction.Count而不是Application.Count
下面的代码调用了一个后期绑定的函数,这使得VBA runtime比必要的要更加努力地查找Count方法。你正在使用扩展COM接口,所以你没有编译时验证。Application.IDontExist可以完美地编译,但在运行时会出现错误438。与任何其他后期绑定成员调用一样,VBE的IntelliSense无法帮助你处理参数。
下面的代码调用的是早期绑定的函数,VBA在编译时解析它。你直接使用WorksheetFunction接口,所以VBE为参数提供了自动完成和IntelliSense。
自动完成:
IntelliSense:
调用是早期绑定的事实意味着没有运行时开销,因此具有更好的性能——即使最终执行的是完全相同的内部Excel函数。
缺点(如果有)是后期绑定的Application.SomeFunction与Excel4Macros兼容,这是自动化Excel的旧遗留预-VBA方式。因此,晚期绑定函数不像早期绑定函数那样引发运行时错误,而是返回错误值,因此您应该使用IsError进行测试,然后才能假定获得的类型。
通过早期绑定WorksheetFunction.SomeFunction调用,如果结果Excel将显示#REF!或#VALUE!、#N/A或任何其他可能的错误值,那么您永远不会因将错误值视为String或Long或任何其他非错误VBA类型而捕获类型不匹配的运行时错误。相反,您只需处理运行时错误,就像处理任何其他VBA API函数调用一样。
晚期绑定调用会将错误值传播到您的代码中;早期绑定调用会“早期失败”:在读取单元格值和使用该值的方式之间可能有20行代码,假设没有错误值,并且“那个指令”抛出了“类型不匹配”的错误 - 然后您需要调试以跟踪返回错误的函数。使用早期绑定代码,函数本身会抛出错误,因此您不必挖掘它。

@ 这是一个过度合格的答案,谢谢。两个琐碎的问题,1. Application.WorksheetFunction.CountWorksheetFunction.Count 是一样的吗?2. 您使用了 IsAllNumeric(ByVal target As Range) 而不是 IsAllNumeric(target As Range)(默认引用版本),这只是个人习惯吗? - Nicholas
是的,WorksheetFunction.CountApplication.WorksheetFunction.Count 是一样的...我只是喜欢过度限定;-) 至于 ByVal,我对 VBA/VB6 默认 ByRef 持有一点怨念(VB.NET 修复了这个问题)。如果指针不需要被函数修改,那么函数就不应该具备这种能力。意外发生得太快了!是的,会有一点“复制指针”的开销。但如果已经成为你的性能瓶颈,那么你已经过度优化了。 - Mathieu Guindon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接