Another approach that tries to avoid string manipulation trades speed for complexity
This uses integer arrays and a 'quick exit' if the string being checked has a char max/min that exceeds the max/min of the allowed characters. No looping this way
Option Explicit
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (dest As Any, src As Any, ByVal bytes As Long)
Function OnlyCertainChar1(ByVal OnlyTheseAllowed As String, ByVal CheckThis As String) As Boolean
Dim i As Long, x As Long
Dim aOnly() As Integer, aCheck() As Integer
ReDim aOnly((LenB(OnlyTheseAllowed) - 1) \ 2)
ReDim aCheck((LenB(CheckThis) - 1) \ 2)
CopyMemory aOnly(0), ByVal StrPtr(OnlyTheseAllowed), LenB(OnlyTheseAllowed)
CopyMemory aCheck(0), ByVal StrPtr(CheckThis), LenB(CheckThis)
With Application.WorksheetFunction
'quick check
OnlyCertainChar1 = False
If .Max(aCheck) > .Max(aOnly) Then Exit Function
If .Min(aCheck) < .Min(aOnly) Then Exit Function
'slower check
OnlyCertainChar1 = True
On Error GoTo NotOnList
For i = LBound(aCheck) To UBound(aCheck)
x = .Match(aCheck(i), aOnly, 0)
Next I
Exit Function
End With
NotOnList:
OnlyCertainChar1 = False
End Function
Sub test()
MsgBox OnlyCertainChar1("ANP*-$#", "ZAAAANNNPPP****----$$$$$#####")
MsgBox OnlyCertainChar1("ANP*-$#", "AAAANNNPPP****----$$$$$#####")
End Sub