【问题标题】:Vectorial formula for cell validation in Excel using VBA使用 VBA 在 Excel 中进行单元格验证的矢量公式
【发布时间】:2016-08-23 22:38:05
【问题描述】:

我正在编写一个 VBA 公式来检查单元格“TestChars”中的所有字符是否被允许,其中“允许”意味着每个字符都出现在由另一个单元格“AllowedChars”定义的列表中。为了让事情变得更加困难,我希望这个公式适用于单元格范围而不是单个单元格。

当前的代码似乎可以工作:

Option Explicit


Public Function AllCharsValid(InputCells As Range, AllowedChars As String) As Boolean
' Check that all characters in InputCells are among
' the characters in AllowedChars

    Dim Char As String
    Dim Index As Integer
    Dim RangeTestChars As Range
    Dim TestChars As String
    For Each RangeTestChars In InputCells
        TestChars = RangeTestChars.Value
        For Index = 1 To Len(TestChars)
            Char = Mid(TestChars, Index, 1)
            If InStr(AllowedChars, Char) = 0 Then
                AllCharsValid = False
                Exit Function
            End If
        Next Index
    Next RangeTestChars
    AllCharsValid = True
End Function

我有以下问题:

  1. 该公式采用一个范围并返回一个布尔值。我更喜欢矢量化函数,在给定输入范围的情况下,您可以获得相应的布尔值范围。似乎像“EXACT”这样的内置公式可以做到这一点(那些你必须按 ctrl-shift-enter 来执行它们的公式以及你得到花括号的地方)。有没有办法使用用户定义的函数来做到这一点?
  2. 我对编程并不陌生,但是我对 VBA 完全陌生(我从今天开始)。上面的代码有什么明显的问题,奇怪的地方吗?
  3. 是否存在会导致公式失败的特殊字符、超长文本或特定输入值?
  4. 有没有更简单的方法来达到同样的效果?代码慢吗?
  5. 当您开始在 Excel 中输入内置公式时,您会收到建议和自动完成功能。这似乎不适用于我的公式,是我要求太多还是有可能实现这一点?

我意识到这个问题包含几个弱相关的子问题,所以我也会很高兴有子答案。

【问题讨论】:

  • 我不认为您可以使用在条件格式规则中返回多个值的数组公式并让它按照您想要的方式工作。 CF 始终是每个单元格的,我认为没有任何机制可以在特定的单元格范围内“分配”返回的真/假数组。
  • 我尝试重新表述我的第一个问题。如果是 Excel,您可以键入 '=AND(EXACT(A1:A10, B1))' 并按 ctrl-shift-enter,这将导致公式显示为 '{=AND(EXACT(A1:A10,B1)) }' 并以矢量方式工作,即 EXACT 将获取输入范围并返回相应的布尔值范围(或数组?)。然后 ALL 函数将折叠此数组并告诉您该范围内的所有单元格是否与 B1 完全相同。目前,要将我的函数用于一系列值,我会执行“=AllCharsValid(A1:A10,B1)”。我可以做 '=AND(AllCharsValid(A1:A10,B1))',至于 'EXACT' 函数吗?
  • 是的,你会从你的函数中返回一个布尔数组,每个单元格一个元素。但目前尚不清楚您为什么要这样做,因为这意味着必须测试每个单元格,而不是在第一个不允许的字符实例上退出并返回 False。
  • AND() 在 Excel 公式中不会短路,因此将评估所有参数。

标签: vba excel validation


【解决方案1】:

以下代码将返回从初始输入范围偏移一列的布尔值范围。只需在 Excel 中创建一个新选项卡并运行 testAllCharsValid 并在 IDE 中显示即时窗口以查看其工作原理。

Sub testAllCharsValid()

    Dim i As Integer
    Dim cll As Range, rng As Range
    Dim allowedChars As String

    ' insert test values in sheet: for testing purposes only
    With ActiveSheet ' change to Thisworkbook.Sheets("NameOfYourSheet")
        Set rng = .Range("A1:A10")
        For i = 1 To 10
            .Cells(i, 1) = Chr(i + 92)
        Next i
    End With

    ' fill allowedChars with letters a to z: for testing purposes only
    For i = 97 To 122
        allowedChars = allowedChars & Chr(i)
    Next i

    ' get boolean range
    Set rng = AllCharsValid(rng, allowedChars)

    ' check if the returned range contains the expected boolean values
    i = 0
    For Each cll In rng
        i = i + 1
        Debug.Print i & " boolean value: " & cll.Value
    Next cll

End Sub

' Check that all characters in InputCells are among
' the characters in AllowedChars
Public Function AllCharsValid(InputCells As Range, allowedChars As String) As Range

    Dim BoolTest As Boolean
    Dim Char As String
    Dim Index As Integer
    Dim RangeTestChars As Range, RangeBooleans As Range, RangeTemp As Range
    Dim TestChars As String
    For Each RangeTestChars In InputCells
        BoolTest = True
        TestChars = RangeTestChars.Value
        For Index = 1 To Len(TestChars)
            Char = Mid(TestChars, Index, 1)
            If InStr(allowedChars, Char) = 0 Then BoolTest = False
        Next Index

        Set RangeTemp = RangeTestChars.Offset(0, 1) ' change offset to what suits your purpose
        RangeTemp.Value = BoolTest

        If RangeBooleans Is Nothing Then
            Set RangeBooleans = RangeTestChars
        Else
            Set RangeBooleans = Union(RangeBooleans, RangeTemp)
        End If

    Next RangeTestChars

    Set AllCharsValid = RangeBooleans

End Function

cf 2) 如果测试字符串的长度为零,该函数将为有问题的单元格返回True,这可能是不可取的。

cf 3) Excel 单元格可以包含的字符数有限制,请阅读更多here。我想,如果你连接一些很长的字符串并将它们发送到函数,你可能会达到 +32767 的整数限制,这会由于整数 Index 变量而导致运行时错误。但是,由于 Excel 单元格的字符限制正好是 +32767,因此该函数应该可以正常工作,没有任何问题。

cf 4) 我不知道。

cf 5) 这不是最容易实现的事情,但可以找到here 的帮助。

【讨论】:

    猜你喜欢
    • 2013-12-26
    • 1970-01-01
    • 2017-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多