VBA或Excel函数以逗号分隔的字符串计数非零

时间:2018-12-02 22:07:42

标签: excel vba

我有一个单元格,其中包含以下内容:[90,90,90,0,90]。

我只想在逗号之前或之后计算非零数字。

因此,在上面的示例中,答案为4,因为“ 90”出现4次。

如果该单元格包含[180,180,0,0,0,0,0,0,90],答案将为3。

是否有VBA或Excel函数(与LEN,SUBSTITUTE,TRIM等一起使用,没有运气)来完成此操作?

谢谢

蒂姆

4 个答案:

答案 0 :(得分:1)

如果您的数据严格如所示:

  • 逗号之间没有空格
  • 没有以零开头的非零数字,例如0180

然后以下效率非常低的公式将起作用:

=(LEN(A1)-LEN(SUBSTITUTE(A1,",",""))) + 1 - (
   (LEN(A1)-LEN(SUBSTITUTE(A1,",0",",")))
  +(LEN(A1)-LEN(SUBSTITUTE(A1,"[0,","[,")))
  +(LEN(A1)-LEN(SUBSTITUTE(A1,",0]",",]")))
)

否则,您可能应该使用VBA:

Public Function CountNonZero(ByVal s As String) As Long
  Dim arr() As String
  arr = Split(Mid$(Trim$(s), 2, Len(s) - 2), ",")

  Dim i As Long
  For i = LBound(arr) To UBound(arr)
    If Trim$(arr(i)) <> "0" Then CountNonZero = CountNonZero + 1
  Next
End Function

答案 1 :(得分:0)

我将逐步构建Excel公式,因此您可以看到该方法。

计划是计算不包含零个元素的字符串的长度,并将其与原始字符串的长度进行比较。

第一步是用空字符串替换任何零元素。但是我们不能只消除所有零,因为非零条目(例如“ 100”)中可以有零。因此,我们需要识别列表条目。

在这里,我假设几件事:

  1. 逗号和列表项之间不会有空格(空白)。
  2. 如果列表项以零开头,则该项为零。换句话说,不允许前导零(例如012)。

如果这些假设中的任何一个错误,我们都可以进行调整。但是,如果我们能够做出这些假设,并且它们与您的示例一致,则更为简单。

因此,我们可以通过用“,”替换“,0”来删除零项。但是我们遇到了障碍。如果将“,0”替换为第一项,则不会找到0。因此,让我们在数字列表的第一个元素之前添加一个逗号。这样我们就可以用“,0”代替。

=Substitute(ref, "[", "[,")

我使用'ref'作为字符串所在的单元格地址。

现在,让我们添加替换以摆脱列表中的0个项:

=Substitute(Substitute(ref, "[", "[,"), ",0", ",")

请注意,我们将第一个(内部)替换的结果用作第二个(外部)替换的输入。

现在,通过将原始字符串的长度与计算出的字符串的长度进行比较,找到要删除的零项的数量:

=Len(ref) - Len(Substitute(Substitute(ref, "[", "[,"), ",0", ",")) + 1

我们需要在公式的末尾添加一个,因为当我们在列表中的第一项之前添加逗号时,计算的字符串要增加一个字符。

在将公式复制到Excel中之前,请记住将“ ref”更改为实际的单元格引用。它出现在公式的两个位置。

答案 2 :(得分:0)

下面的数组公式将满足您的要求。

要输入/确认数组公式,请在按下 enter 的同时按住 ctrl + shift 。如果正确执行此操作,Excel会在公式栏中显示的公式周围放置括号{...}

=SUM(--IFERROR(-TRIM(MID(SUBSTITUTE(A1,",",REPT(" ",99)),seq_99,99))<>0,0))

其中seq_99是一个引用以下内容的命名公式:

=IF(ROW(INDEX($1:$65535,1,1):INDEX($1:$65535,255,1))=1,1,(ROW(INDEX($1:$65535,1,1):INDEX($1:$65535,255,1))-1)*99)
  • SUBSTITUTE用99个空格替换每个逗号
  • MID函数,其seq_99的公式为start_number,将返回一个值数组,其值从{1,99,198,297,...}`开始,分别是字符串中的值。
  • TRIM从每个数组元素中删除多余的空格
  • -将数字的字符串表示形式转换为数字值
    • 这将为数组中的空字符串返回错误
  • 然后我们测试数组中的每个元素以查看它是否不是零。
    • 这将返回`{TRUE,FALSE,#VALUE!,...}的数组
    • IFERROR会将错误转换为零
  • 然后求和将所有TRUE的值相加(Excel中的TRUE = +1)

对于VBA方法:

Option Explicit
Function nonZero(s As String) As Long
    Dim v, w
    Dim l As Long
v = Split(s, ",")
For Each w In v
    If Val(w) <> 0 Then l = l + 1
Next w
nonZero = l
End Function

编辑 我假设您显示的括号[…]实际上不在单元格中,但是显示了单元格边界。如果他们实际上可能不在单元格中,则应将上面的公式修改为:

=SUM(--IFERROR(-TRIM(MID(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(A1,"[",""),"]",""),",",REPT(" ",99)),seq_99,99))<>0,0))

或用户定义的功能可以

Option Explicit
Function nonZero(s As String) As Long
    Dim v, w
    Dim l As Long
    Dim str As String
str = Replace(s, "[", "")
str = Replace(str, "]", "")

v = Split(str, ",")
For Each w In v
    If Val(w) <> 0 Then l = l + 1
Next w
nonZero = l
End Function

答案 3 :(得分:-1)

很明显,我原来的回答没有帮助。

这是我的最新答案:

Public Function NonZero(str As String) As Integer

    NonZero = 0
    str = Replace(Replace(Replace(str, " ", ""), "[", ""), "]", "") ' get rid of bracket & space, or whatever...


    Dim x As Integer
    Do While Len(str) > 0

        x = InStr(1, str, ",")
        If x = 1 Then       'start with ","
            str = Right(str, Len(str) - 1)
            x = InStr(1, str, ",")
        End If

        If x > 0 Then
            If Val(Left(str, x - 1)) <> 0 Then
                NonZero = NonZero + 1
            End If
            str = Right(str, Len(str) - x)
        Else
            If Val(str) <> 0 Then
                NonZero = NonZero + 1

            End If
            str = ""
        End If
    Loop

End Function

测试结果: enter image description here