在字符串中查找特定数字?

Finding specific number inside a string?

这是我的数据样本,其中 name 在单元格 A1 中。 C 列不是数据的一部分,它只是为了说明需要什么。

name    cod     should be detected?
aa              no  
aa      14;15   no
aa      1;13;7  yes 
bb      8;9;1   yes 
bb      1;17    yes 
bb      11;21   no
cz      7;8     no  
cz      7;21    no
cz      8;1;20  yes 
db      1       yes 
db      13;1    yes 

我正在尝试编写一个宏来检测 cod 列中出现数字 1 的位置。比如我不想找10、13、21,而是1。此栏中填写的数字从 1 到 21。

所有 cod 值都是字符串,但我想找到 1 的位置,即使它与字符串中的其他数字混合出现。此列中的数字始终用 ; 分隔,中间没有空格。

下面的代码会产生假 positives:

Dim N As Range
Dim msg As String

Sub cod1()

msg = ""

For Each N In Range("A2", Range("A2").End(xlDown))
    If InStr(1, N.Offset(, 1), 1, vbTextCompare) > 0 Then
                msg = msg & "Code 1 was not supposed to be in Cod column." & vbLf
            Exit For
    End If
Next N

    If Len(msg) > 1 Then
        MsgBox msg
    Else: MsgBox "There are no code 1 values in Cod column."
    End If

End Sub

查看结果:

name    cod     should be detected? problem
aa              no  
aa      14;15   no                  false positive
aa      1;13;7  yes 
bb      8;9;1   yes 
bb      1;17    yes 
bb      11;21   no                  false positive
cz      7;8     no  
cz      7;21    no                  false positive
cz      8;1;20  yes 
db      1       yes 
db      13;1    yes 

下面的代码会产生错误的negatives:

Dim N As Range
Dim msg As String

Sub cod2()

msg = ""

For Each N In Range("A2", Range("A2").End(xlDown))
    If InStr(1, N.Offset(, 1), 1, vbTextCompare) > 0 And _
        InStr(1, N.Offset(, 1), 10, vbTextCompare) = 0 And _
        InStr(1, N.Offset(, 1), 11, vbTextCompare) = 0 And _
        InStr(1, N.Offset(, 1), 12, vbTextCompare) = 0 And _
        InStr(1, N.Offset(, 1), 13, vbTextCompare) = 0 And _
        InStr(1, N.Offset(, 1), 14, vbTextCompare) = 0 And _
        InStr(1, N.Offset(, 1), 15, vbTextCompare) = 0 And _
        InStr(1, N.Offset(, 1), 16, vbTextCompare) = 0 And _
        InStr(1, N.Offset(, 1), 17, vbTextCompare) = 0 And _
        InStr(1, N.Offset(, 1), 18, vbTextCompare) = 0 And _
        InStr(1, N.Offset(, 1), 19, vbTextCompare) = 0 And _
        InStr(1, N.Offset(, 1), 21, vbTextCompare) = 0 Then
            msg = msg & "Code 1 was not supposed to be in Cod column." & vbLf
        Exit For
    End If
Next N

    If Len(msg) > 1 Then
        MsgBox msg
    Else: MsgBox "There are no code 1 values in Cod column."
    End If

End Sub

查看结果:

name    cod     should be detected? problem
aa              no  
aa      14;15   no  
aa      1;13;7  yes                 false negative
bb      8;9;1   yes 
bb      1;17    yes                 false negative
bb      11;21   no  
cz      7;8;10  no  
cz      7;21    no  
cz      8;1;20  yes                 false negative
db      1       yes 
db      13;1    yes                 false negative

那么,如何才能让消息框*仅在字符串中检测到数字 1 时出现?

*Code 1 was not supposed to be in Cod column.


寻找适用于 Excel 2007 和更新版本的解决方案。

您可以使用Like运算符查找字符:

Dim N As Range
Dim msg As String

Sub cod1()

    Dim expression As String
    msg = ""

    For Each N In Range("A2", Range("A2").End(xlDown))
        expression = ";" & N.Offset(, 1) & ";"
        If expression Like "*;1;*" Then
           msg = msg & "Code 1 was not supposed to be in Cod column." & vbLf
        End If
    Next N

    If Len(msg) > 1 Then
        MsgBox msg
    Else
        MsgBox "There are no code 1 values in Cod column."
    End If

End Sub

或者,您可以使用通用 UDF(用户定义函数)检测单元格内是否存在任何值,使用任何分隔符:

Public Function hasItem(ByVal r As Range, item As Variant, sep As String) As Boolean
    ar = Split(r.Text, sep)
    For Each x In ar
        If Trim(CStr(x)) = Trim(CStr(item)) Then
           hasItem = True
           Exit Function
        End If
    Next
End Function

将上述 UDF 放入代码模块 Module1 中,并在 C 列的单元格中像这样使用它,即 C1:

=IF(hasItem(B1, 1, ";"), "yes", "no")

然后您可以 copy/paste 它在所有 C 个单元格中。 此外,您可以在任何 VBA 代码中方便地使用该功能来显示您想要的消息。

此解决方案使用 Split 函数在 B 列中生成一个值数组,然后比较每个数组项。

Sub Test()
Dim rDta As Range, rRow As Range
Dim aRow As Variant, vItm As Variant
Dim sMsg As String, lRow As Long

    With ThisWorkbook.Sheets("DATA.3").Cells(1).CurrentRegion   'change as required
        Set rDta = .Offset(1).Resize(-1 + .Rows.Count)
    End With

    lRow = 1
    For Each rRow In rDta.Rows
        lRow = 1 + lRow
        aRow = Split(rRow.Cells(2).Value2, ";")
        For Each vItm In aRow
            If vItm = 1 Then
                If sMsg = vbNullString Then sMsg = "Code 1 was not supposed to be in Cod column of rows:"
                    sMsg = sMsg & vbLf & vbTab & lRow
                rRow.Cells(1, 3).Value = "Code 1 was not supposed to be in Cod column." 'Remove if required
    End If: Next: Next

    If sMsg = vbNullString Then sMsg = "There are no code 1 values in Cod column."
    MsgBox sMsg

End Sub