【问题标题】:Count cells that contain certain letters (Visual Basic)计算包含某些字母的单元格 (Visual Basic)
【发布时间】:2016-12-12 03:55:31
【问题描述】:

我正在尝试在 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

所以我的输入是 =letters(A1:B6),假设 B2、B3 和 B5 有文本“PD”。我希望我的答案是 3,但我得到了 #value!错误。我哪里错了?

提前致谢。

【问题讨论】:

  • 一些建议,limit = list.Rows.Countif list(i, 2) = "PD" Then。 list(i, 2) 将遍历第二列每一行中的单元格,如果那是你想要的
  • 非常简单的解决方案。 WorksheetFunction.CountIf(Range("A1:A25"), "PD")
  • 更容易的是直接在工作表中使用 COUNTIF。无需编写自定义函数。我觉得 OP 想要匹配单元格内容中任何位置的文本
  • nightcrawler23 @barney 你的回答很有道理。我想对我来说接下来的事情是我想知道为什么我会得到#value!错误。我想知道我的代码行是什么给了我错误,以便我进一步了解数据类型等。
  • 旁注:如果Double 变量只处理整数,则不要使用它。您可以改用Integer

标签: excel vba


【解决方案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

此外,该函数适用于单列中的范围。

【讨论】:

    【解决方案2】:

    回答你的问题

    我哪里错了?

    有几点需要解决:

    • 你说你用

      调用你的函数
       =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) 方法将引用一个范围,该范围与您在其参数中输入的行和列所调用的范围“偏移”。所以当i=1 时Offset(i,2) 调用Range("A1:B6") 引用Range("C2:D7"),当i=2 时Range("C3:D8") 等等

          到:

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

          Cells(iRow, iColumn) 方法将引用被调用的RangeiRowth 行和iColumnth 列中的单元格。所以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
        

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

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

      • 声明您的 FunctionLong 类型

        因为:

        • 您返回的是整数值,因此无需使用 Double 类型

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

      • 声明Dim limit As Long

        自从

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

        您正在为其分配 Range 的实际行数,它可能超过 Integer 类型变量的 65k 限制


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

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

    您将使用Range 对象的.Columns(n) 属性来引用被调用的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")
    

    【讨论】:

    • @Soto,你通过了吗?
    • 您的解决方案很有意义,但我没有尝试所有建议。我想出了一个经过测试的解决方案。
    • 您的解决方案很有意义,但我没有尝试所有建议。我想出了一个经过测试的解决方案。我很抱歉。我是否在此评论中发布我的答案?还是我回答我自己的问题。我也接受你的回答吗?不知道这里的标准是什么。我对 stackoverflow.com 还很陌生。
    • 好吧,您发布了您的代码并提出了一个问题“我哪里出错了?”如果有满足此类请求的答案,您应该将其标记为已接受。我看到有一个已经标记的答案:如果这是您认为最符合您的要求的答案,而不是保留它。否则改变。除此之外,您仍然可以使用您提出的代码发布答案。您可以查看this relevant help topic 以获得更完整的监督。
    【解决方案3】:

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

    =SUMPRODUCT(--(IFERROR(FIND("PD",A1:A25,1)>0,FALSE)))
    

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

    FIND("PD",A1:A25,1) 为您提供文本位置,如果没有为每个单元格找到文本,则为您提供错误。

    &gt;0 将数字转换为 TRUE。如果出现错误IFERROR,则将其转换为 FALSE。因此,您会得到 TRUEsFALSEs 的数组,例如 {TRUE,FALSE,...}

    --({...}) 将数组转换为 1 和 0。 TRUE 为 1,FALSE 为 0。 SUMPRODUCT 添加这个数字数组来给你计数。

    【讨论】:

      猜你喜欢
      • 2021-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-13
      • 2023-02-21
      • 1970-01-01
      • 1970-01-01
      • 2013-07-24
      相关资源
      最近更新 更多