计算包含特定字母的单元格(Visual Basic)

时间:2016-12-12 03:55:32

标签: excel vba

我正在尝试在VBA中编写一个函数来计算包含特定范围内某些字母的单元格。到目前为止,我的代码是

Function letters(list As range) As Double

    Dim limit As Integer
    limit = UBound(list.Value)

    Dim total As Double
    total = 0

    Dim i As Integer

    For i = 1 To limit
        If range(list).Offset(i, 2) = "PD" Then
        total = total + 1
        End If
    Next i

    letters = total

End Function

所以我的输入是=字母(A1:B6),让我们说B2,B3和B5的文字是“PD”。我希望我的答案是3,但我得到#value!错误。我哪里错了?

提前致谢。

3 个答案:

答案 0 :(得分:1)

您可以遍历范围中的每个单元格,并使用INSTR查找单元格是否包含文本。如果计数器增加计数器然后输出它。

Function findText(myRange As Range, toFind As String)
    Dim ra As Range
    Dim rCount As Integer
    rCount = 0


    For i = 1 To myRange.Rows.Count
        If InStr(1, myRange(i, 1), toFind, vbTextCompare) Then
            rCount = rCount + 1
        End If
    Next i

    findText = rCount

End Function

这将计算在单元格中任何位置具有所需文本的单元格的事件。如果要匹配整个单元格内容,只需使用

即可
If myRange(i, 1) = toFind Then

此外,该功能适用​​于单列范围。

答案 1 :(得分:1)

回答你的问题

  

我哪里错了?

有一些问题需要解决:

  • 你说你用

    打电话给你的功能
     =letters(A1:B6)
    

    但是A1:B6并不意味着什么,而你有两个选择:

    • 要么将您的函数调用为文字string作为有效的Range地址

      =letters("A1:B6")

    • 或者您称之为直接传递Range对象

      =letters(Range("A1:B6"))

  • 一旦你完成了前一点,你必须采取一致行动,即:

    • 选项1:将文字string作为有效Range地址传递

      然后"A1:B6"(请注意围绕A2:B6的双引号)是您的范围的地址,因此您必须:

      • 变化:

        limit = UBound(list.Value) '<--| error
        

        string没有Value属性

        到:

        limit = UBound(Range(list).Value) '<--| OK
        

        Range("A1:B6")是有效的Range参考,因此您可以访问其Value属性

      • 变化:

        Range(list).Offset(i, 2) '<--| this references a range as large as the one it's being called upon! 
        

        Offset(nRows, nColumns)方法将引用一个范围,该范围从被调用的范围“移位”到您放入其参数的行数和列数。因此,当Offset(i,2) = 1时,Range("A1:B6")引用Range("C2:D7")引用iRange("C3:D8") = 2时引用i,依此类推

        为:

        Range(list).Cells(i, 2) '<--| it references a single cell
        

        Cells(iRow, iColumn)方法将引用正在调用的iRow iColumn行和Range列中的单元格。所以Range("A1:B6").Cells(1,2)引用单元格“B7”

    • 选项2:传递Range对象

      由于list已经是Range个对象(即Range("A1:B6")),您必须:

      • 变化:

        If Range(list).Offset(i, 2) = "PD" Then '<--| error
        

        您无法将Range对象作为另一个Range对象的唯一参数传递

      为:

          If list.Cells(i, 2) = "PD" Then '<--| Ok
      

      您使用Cells对象的Range属性,如选项1中所述

  • 那么您可能需要考虑以下 miscellanea

    • Function类型

      声明您的Long

      自:

      • 您将返回一个整数值,因此无需使用Double类型

      • 行数可超过Integer类型变量的65 k限制

    • 声明Dim limit As Long

      因为

       limit = UBound(Range(list).Value) '<--| correct use of 'list' if it's a literal 'string'
      

      你要为它指定一个范围的实际行数,它可能会超过Integer类型变量的约65k限制

所有这一切,我认为最有效的VBA解决方案是使用WorksheetFunction.CountIF()函数,如下所示:

Function letters(list As String) As Long
    letters = WorksheetFunction.CountIf(Range(list).Columns(2), "PD")
End Sub

您使用.Columns(n)对象的Range属性来引用它被调用的Range的第n列

通过将其参数列表扩展为搜索的字符串

,您可以更加通用
Function letters(list As String, myLetters As String) As Long
    letters = WorksheetFunction.CountIf(Range(list).Columns(2), myLetters)
End Sub 

你打电话给:

MsgBox letters("A1:B6", "PD")

答案 2 :(得分:0)

如果您愿意,您可以通过使用以下公式而不是使用VBA来实现此目的。

b_memcpy.vfunc()

您需要输入此数组公式,即输入公式并按 Ctrl Shift Enter

如果找不到每个单元格的文本,

=SUMPRODUCT(--(IFERROR(FIND("PD",A1:A25,1)>0,FALSE))) 会为您提供文本位置或错误。

FIND("PD",A1:A25,1)将数字转换为TRUE。如果错误>0将其转换为FALSE。因此,您获得了IFERRORTRUEs的数组FALSEs

{TRUE,FALSE,...}将数组转换为1和0。 --({...})为1,TRUE为0。 FALSE添加了这个数字数组,以便为​​您提供计数。