Page 1 of 2 12 LastLast
Results 1 to 40 of 73

Thread: instr Count

  1. #1

    Thread Starter
    Fanatic Member aconybeare's Avatar
    Join Date
    Oct 2001
    Location
    UK
    Posts
    772

    Resolved instr Count

    Hi,

    I've got a basic instr count function, can anyone see any flaws in it or any way of tweaking it to make it more efficient without making api calls etc.

    VB Code:
    1. Private Sub Command1_Click()
    2.     Debug.Print InStrCount("the quick brown fox jumped over the lazy dog", " ") & vbNewLine
    3. End Sub
    4.  
    5. Private Function InStrCount(ByVal Expression As String, _
    6.                         ByVal Find As String, _
    7.                         Optional ByVal Start As Long = 1, _
    8.                         Optional ByVal Count As Long = -1, _
    9.                         Optional Compare As VbCompareMethod = vbBinaryCompare) As Long
    10.     Dim Temp$, h As Long
    11.     On Error Resume Next ' handle div by zero
    12.     Temp$ = Replace(Expression, Find, "", Start, Count, Compare)
    13.     h = CLng(LenB(Expression) - LenB(Temp$))
    14.     h = CLng(h \ LenB(Find))
    15.     InStrCount = h
    16. End Function

    Any help or pointers will be gratefully received

    Cheers Al
    Last edited by aconybeare; Jun 23rd, 2005 at 03:04 AM. Reason: Resolved

  2. #2
    Hyperactive Member
    Join Date
    Jul 2002
    Location
    WGTN, New Zealand
    Posts
    338

    Re: instr Count

    That's not terribly efficient, you want the data that you are searching to be constant, as in, you don't want it to change. If the string is passed by a reference as opposed to by value, a new copy of the string won't have to be made, making it more efficient for longer strings.

    Also, you don't want to use the On Error Resume Next statement. If that is purely to avoid a division by zero, you should check for a zero length string before trying to complete the entire subroutine.

    I'm not too sure, but see if Replace() also has a Replace$() equivalent. The difference between the two being that Replace() returns a variant (which later is converted back to a string), but the Replace$() version returns a string.

  3. #3

    Thread Starter
    Fanatic Member aconybeare's Avatar
    Join Date
    Oct 2001
    Location
    UK
    Posts
    772

    Re: instr Count

    DreamLax,

    Thanks for the tips here is the updated function -

    VB Code:
    1. Private Function InstrCount(ByVal Expression As String, _
    2.                         ByVal Find As String, _
    3.                         Optional ByVal Start As Long = 1, _
    4.                         Optional Compare As VbCompareMethod = vbBinaryCompare) As Long
    5.                        
    6.     Dim Temp$, h As Long
    7.     If LenB(Find) Then    ' check for zero length find; avoid div by zero
    8.         Temp$ = Replace$(Expression, Find, "", Start, -1, Compare)
    9.         h = CLng(LenB(Expression) - LenB(Temp$))
    10.         h = CLng(h \ LenB(Find))
    11.     End If
    12.     InstrCount = h
    13. End Function

    Regards Allan

  4. #4

    Thread Starter
    Fanatic Member aconybeare's Avatar
    Join Date
    Oct 2001
    Location
    UK
    Posts
    772

    Re: instr Count

    Hi,

    I forgot to change the byVal's to byRef.

    I've also put the "h" assignment onto one line to avoid two calls to clng.

    I've read that Division is very slow. Does anyone know if there is a way of converting into a decimal so that I can multiply rather, I've hi-lited the spot in question

    VB Code:
    1. Private Function InstrCount(ByRef Expression As String, _
    2.                         ByRef Find As String, _
    3.                         Optional ByRef Start As Long = 1, _
    4.                         Optional Compare As VbCompareMethod = vbBinaryCompare) As Long
    5.                        
    6.     Dim Temp$, h As Long
    7.     If LenB(Find) Then    ' check for zero length find; avoid div by zero
    8.         Temp$ = Replace$(Expression, Find, "", Start, -1, Compare)
    9.         h = CLng((LenB(Expression) - LenB(Temp$)) [HL="#FFFF00"]/ LenB(Find)[/HL])
    10.     End If
    11.     InstrCount = h
    12. End Function

    Cheers Al

  5. #5
    I'm about to be a PowerPoster!
    Join Date
    Jan 2005
    Location
    Everywhere
    Posts
    13,647

    Re: instr Count

    Here this was about as fast as I could get it
    VB Code:
    1. Private Function InStrCount(ByRef Expression As String, _
    2.                             ByRef Find As String, _
    3.                             Optional ByVal Start As Long = 1, _
    4.                             Optional Compare As VbCompareMethod = vbBinaryCompare) _
    5.                            As Long
    6.     Dim Temp$
    7.     If (LenB(Find)) Then
    8.         Temp$ = Replace$(Expression, Find, vbNullString, Start, -1, Compare)
    9.         InStrCount = CLng((LenB(Expression) - LenB(Temp$)) \ LenB(Find))
    10.     End If
    11. End Function

  6. #6

    Thread Starter
    Fanatic Member aconybeare's Avatar
    Join Date
    Oct 2001
    Location
    UK
    Posts
    772

    Re: instr Count

    Nice one Penagate, thanks a bunch!

  7. #7
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: instr Count

    Handling strings is slow -> Replace$ is slow. Original InStr is VERY fast. InStrB is even a bit faster (as far as I remember).

    VB Code:
    1. Private Function InStrCount(ByRef Expression As String, _
    2.                             ByRef Find As String, _
    3.                             Optional ByVal Start As Long = 1, _
    4.                             Optional Compare As VbCompareMethod = vbBinaryCompare) _
    5.                             As Long
    6.     Dim Position As Long, Count As Long
    7.     Position = InStrB(Start, Expression, Find, Compare)
    8.     Do While Position > 0
    9.         Count = Count + 1
    10.         Position = InStrB(Position + 2, Expression, Find, Compare)
    11.     Loop
    12.     InStrCount = Count
    13. End Function

  8. #8

    Thread Starter
    Fanatic Member aconybeare's Avatar
    Join Date
    Oct 2001
    Location
    UK
    Posts
    772

    Re: instr Count

    Merri,

    Thanks for the function unfortunately it doesn't work correctly. I've tested it using the below functions, however I get the idea

    Cheers Al

    VB Code:
    1. Public Function IsGoodInStrCount(Optional fLigaturesToo As Boolean) As Boolean
    2. ' verify correct InStrCount returns, 20021005
    3. ' returns True if all tests are passed
    4.  
    5.   ' replace "InStrCount" with the name of your function to test
    6.   Dim fFailed As Boolean
    7.   Dim Text As String
    8.  
    9.   If InStrCount("ababa", "a") <> 3 Then Stop: fFailed = True
    10.   If InStrCount("ababa", "ab") <> 2 Then Stop: fFailed = True
    11.   If InStrCount("ababa", "aba") <> 1 Then Stop: fFailed = True
    12.   If InStrCount("ababa", "abb") <> 0 Then Stop: fFailed = True
    13.   If InStrCount("ababa", "") <> 0 Then Stop: fFailed = True
    14.   If InStrCount("", "a") <> 0 Then Stop: fFailed = True
    15.   If InStrCount("aaaa", "aa") <> 2 Then Stop: fFailed = True
    16.  
    17.   If InStrCount("aAaA", "a") <> 2 Then Stop: fFailed = True
    18.   If InStrCount("aAaA", "a", , vbTextCompare) <> 4 Then Stop: fFailed = True
    19.   If InStrCount("aAaA", "A", , vbTextCompare) <> 4 Then Stop: fFailed = True
    20.  
    21.   ' unicode
    22.   If InStrCount("€€€", "€") <> 3 Then Stop: fFailed = True
    23.   If InStrCount("[a]{a}", "{A}", , vbTextCompare) <> 1 Then Stop: fFailed = True
    24.  
    25.   ' Common chars when parsing Unix "man" pages...
    26.   Text = Replicate05(10, "{|}[/][\]{{||}}[/][\]{{{|||}}}[/][\]")
    27.   If InStrCount(Text, "{|}", , vbTextCompare) <> 10 Then Stop: fFailed = True
    28.  
    29.   ' the 4 stooges: š/Š, œ/Œ, ž/Ž, ÿ/Ÿ (154/138, 156/140, 158/142, 255/159)
    30.   If InStrCount("Hašiš", "Š", , vbTextCompare) <> 2 Then Stop: fFailed = True
    31.   ' ligatures  textcompare (VBspeed entries do NOT have to pass this test)
    32.   If fLigaturesToo Then
    33.     ' ligatures, a digraphemic fun house: ss/ß, ae/æ, oe/œ, th/þ
    34.     If InStrCount("Straße", "ss", , vbTextCompare) <> 1 Then Stop: fFailed = True
    35.   End If
    36.    
    37.   ' well done
    38.   IsGoodInStrCount = Not fFailed
    39.  
    40. End Function
    41.  
    42. Public Function Replicate05(ByVal Number&, Pattern$) As String
    43. ' by Donald, [email][email protected][/email], 20001206, rev 002
    44. ' based on Replicate03 by Larry Serflaten, [email][email protected][/email], 20001206
    45.  
    46.   Dim LP As Long
    47.  
    48.   If Number > 0 Then
    49.     LP = Len(Pattern)
    50.     Select Case LP
    51.     Case Is > 1
    52.       Replicate05 = Space$(Number * LP)
    53.       Mid$(Replicate05, 1, LP) = Pattern
    54.       If Number > 1 Then
    55.         Mid$(Replicate05, LP + 1) = Replicate05
    56.       End If
    57.     Case 1
    58.       Replicate05 = String$(Number, Pattern)
    59.     End Select
    60.   End If
    61.  
    62. End Function

  9. #9
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: instr Count

    VB Code:
    1. Private Function InStrCount(ByRef Expression As String, _
    2.                             ByRef Find As String, _
    3.                             Optional ByVal Start As Long = 1, _
    4.                             Optional Compare As VbCompareMethod = vbBinaryCompare) _
    5.                             As Long
    6.     Dim Position As Long, Count As Long, Length As Long
    7.     Length = Len(Find)
    8.     If Length > 0 Then
    9.         Position = InStr(Start, Expression, Find, Compare)
    10.         Do While Position > 0
    11.             Count = Count + 1
    12.             Position = InStr(Position + Length, Expression, Find, Compare)
    13.         Loop
    14.         InStrCount = Count
    15.     End If
    16. End Function

    InStrB doesn't like TextCompare.

  10. #10

    Thread Starter
    Fanatic Member aconybeare's Avatar
    Join Date
    Oct 2001
    Location
    UK
    Posts
    772

    Re: instr Count

    Merri,

    That's spot on! I've tested the speed and these are the results

    my function -

    Call1: 1000 Time: 1.129
    Call2: 1000 Time: 1.157
    Call3: 1000 Time: 1.057
    Call4: 1000 Time: 1.896
    Call5: 100 Time: 0.192
    Call6: 100 Time: 0.213

    your function -

    Call1: 1000 Time: 0.27
    Call2: 1000 Time: 51.79
    Call3: 1000 Time: 0.27
    Call4: 1000 Time: 52.9
    Call5: 100 Time: 0.04
    Call6: 100 Time: 6.18

    test details -
    Call 1
    String1 = Replicate(1000, "abcd")
    String2 = "b"
    Compare = vbBinaryCompare

    Call 2
    String1 = Replicate(1000, "abcd")
    String2 = "B"
    Compare = vbTextCompare

    Call 3
    String1 = Replicate(1000, "abcd")
    String2 = "bc"
    Compare = vbBinaryCompare

    Call 4
    String1 = Replicate(1000, "abcd")
    String2 = "BC"
    Compare = vbTextCompare

    Call 5
    String1 = Replicate(100, "The quick brown fox jumped over the lazy dogs")
    String2 = "jumped over"
    Compare = vbBinaryCompare

    Call 6
    String1 = Replicate(100, "The Quick Brown Fox Jumped Over The Lazy Dogs")
    String2 = "jumped over"
    Compare = vbTextCompare

    As is so often the case with these things it's 6 of one and half a dozen of the other

  11. #11
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: instr Count

    In which case we combine the good things:

    VB Code:
    1. Private Function InStrCount(ByRef Expression As String, _
    2.                             ByRef Find As String, _
    3.                             Optional ByVal Start As Long = 1, _
    4.                             Optional Compare As VbCompareMethod = vbBinaryCompare) _
    5.                             As Long
    6.     Dim Position As Long, Count As Long, Length As Long, Temp As String
    7.     Length = CLng(LenB(Find))
    8.     If Length > 0 Then
    9.         If Compare = vbBinaryCompare Then
    10.             Position = InStrB(Start, Expression, Find, Compare)
    11.             Do While Position > 0
    12.                 Count = Count + 1
    13.                 Position = InStrB(Position + Length, Expression, Find, vbBinaryCompare)
    14.             Loop
    15.             InStrCount = Count
    16.         Else
    17.             Temp = Replace$(Expression, Find, vbNullString, Start, -1, Compare)
    18.             InStrCount = CLng(LenB(Expression) - LenB(Temp)) \ Length
    19.         End If
    20.     End If
    21. End Function

    And then they lived happily ever after.

  12. #12

    Thread Starter
    Fanatic Member aconybeare's Avatar
    Join Date
    Oct 2001
    Location
    UK
    Posts
    772

    Re: instr Count

    Nice one Merri, thanks for all your help

    Cheers Al

  13. #13
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: instr Count

    Out of interest: did you make a comparison with old codes vs. the final result?

  14. #14

    Thread Starter
    Fanatic Member aconybeare's Avatar
    Join Date
    Oct 2001
    Location
    UK
    Posts
    772

    Thumbs up Re: instr Count

    Merri,

    My original test was done on my home PC, these were done at work. Here you go -

    Your Hybrid function -
    Call1: 1000 Time: 0.27
    Call2: 1000 Time: 0.82
    Call3: 1000 Time: 0.25
    Call4: 1000 Time: 0.69
    Call5: 100 Time: 0.04
    Call6: 100 Time: 0.17


    Your Original -
    Call1: 1000 Time: 0.308
    Call2: 1000 Time: 55.341
    Call3: 1000 Time: 0.325
    Call4: 1000 Time: 57.292
    Call5: 100 Time: 0.039
    Call6: 100 Time: 6.293


    My Original -
    Call1: 1000 Time: 0.66
    Call2: 1000 Time: 0.671
    Call3: 1000 Time: 0.598
    Call4: 1000 Time: 0.659
    Call5: 100 Time: 0.075
    Call6: 100 Time: 0.142



    Since your function is a hybrid I can only think that the reason it doesn't win all tests is because there are more lines of code to process in the hybrid function, they're very tightly run so the hyrid is the way forward.

    Cheers Al
    Last edited by aconybeare; Jun 23rd, 2005 at 03:11 AM.

  15. #15
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: instr Count

    Yeah, extra comparisons cause minor drawback; atleast LenB can be proven to be faster than InStr

    I don't know if you did a complete benchmark or not; are these one run only or avarage on multiple runs? Not that it matters too much, it is fast enough as it is

  16. #16

    Thread Starter
    Fanatic Member aconybeare's Avatar
    Join Date
    Oct 2001
    Location
    UK
    Posts
    772

    Re: instr Count

    Merri,

    Just one run comparisons

    Cheers Al

  17. #17

    Thread Starter
    Fanatic Member aconybeare's Avatar
    Join Date
    Oct 2001
    Location
    UK
    Posts
    772

    Re: instr Count

    Merri,

    On another topic I just noticed in your signature your postings on PSC which I've checked out and I'm interested in your InBArr and InBArrRev functions I've downloaded it but am getting load errors with frmTest -

    Taken from frmTest.log
    Line 17: Property ItemData in Combo1 had an invalid file reference.
    Line 19: Property List in Combo1 had an invalid file reference.

    What references do I need? microsoft windows common controls?

    Plus getting invalid property value error in -

    VB Code:
    1. Private Sub Form_Load()
    2.     [HL="#FFFF00"]Combo1.ListIndex = 0[/HL]    
    3.     TestFile = "c:\autoexec.bat"
    4.     KeyWord = "select"
    5.     Iterations = 100000
    6. End Sub
    Any ideas?

    Cheers Al

  18. #18
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: instr Count

    There just should be two items items in the ComboBox, I can't remember what it says in them as I'm not in the computer where I have the source. Just add two items to the combobox (like, 1 and 2) and try if it works then.

  19. #19

    Thread Starter
    Fanatic Member aconybeare's Avatar
    Join Date
    Oct 2001
    Location
    UK
    Posts
    772

    Re: instr Count

    Yar thanks I've sorted it, added in all the compare options manually.

    I'm just knocking out an email to you via PSC. Rather than posting off topic here. Don't want to offend anyone

    Cheers Al

  20. #20
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: instr Count

    Here is a new version of InBArr.

    Code:
    Option Explicit
    Public Function InBArr(ByRef ByteArray() As Byte, ByRef KeyWord As String, Optional StartPos As Long = 0, Optional Compare As Byte = vbBinaryCompare, Optional IsUnicode As Boolean = True) As Long
        Static KeyBuffer() As Byte, KeyBufferU() As Byte
        Dim A As Long, B As Long, C As Long, KeyLen As Long, KeyUpper As Long
        Dim FirstKeyByte As Byte, LastKeyByte As Byte, TempByte As Byte
        Dim FirstKeyByte2 As Byte, LastKeyByte2 As Byte, TempByte2 As Byte
        Dim FirstKeyByteU As Byte, LastKeyByteU As Byte
        Dim FirstKeyByte2U As Byte, LastKeyByte2U As Byte
        If (Not ByteArray) = True Then InBArr = -1: Exit Function
        If LenB(KeyWord) = 0 Then InBArr = StartPos: Exit Function
        If Compare = vbBinaryCompare Then
            KeyBuffer = KeyWord
        Else
            KeyBufferU = UCase$(KeyWord)
            KeyBuffer = LCase$(KeyWord)
        End If
        KeyLen = UBound(KeyBuffer) - 1
        KeyUpper = KeyLen \ 2
        If KeyUpper > UBound(ByteArray) Then InBArr = -1: Exit Function
        If StartPos < 0 Then StartPos = 0
        If IsUnicode Then
            If (StartPos Mod 2) = 1 Then StartPos = StartPos - (StartPos Mod 2) + 2
            If StartPos > UBound(ByteArray) - KeyLen Then StartPos = UBound(ByteArray) - KeyLen
            FirstKeyByte = KeyBuffer(0)
            LastKeyByte = KeyBuffer(KeyLen)
            FirstKeyByte2 = KeyBuffer(1)
            LastKeyByte2 = KeyBuffer(KeyLen + 1)
            If Compare = vbBinaryCompare Then
                'loop through the array
                For A = StartPos To UBound(ByteArray) - KeyLen - 1 Step 2
                    If ByteArray(A) = FirstKeyByte And ByteArray(A + 1) = FirstKeyByte2 Then
                        If ByteArray(A + KeyLen) = LastKeyByte And ByteArray(A + KeyLen + 1) = LastKeyByte2 Then
                            If KeyLen > 4 Then
                                'check if keyword is found from the array
                                C = A + 2
                                For B = 2 To KeyLen - 1 Step 2
                                    If Not (ByteArray(C) = KeyBuffer(B) And ByteArray(C + 1) = KeyBuffer(B + 1)) Then Exit For
                                    C = C + 2
                                Next B
                                'keyword is found!
                                If B >= KeyLen Then
                                    InBArr = A
                                    Exit Function
                                End If
                            Else
                                InBArr = A
                                Exit Function
                            End If
                        End If
                    End If
                Next A
            Else 'vbTextCompare
                FirstKeyByteU = KeyBufferU(0)
                LastKeyByteU = KeyBufferU(KeyLen)
                FirstKeyByte2U = KeyBufferU(1)
                LastKeyByte2U = KeyBufferU(KeyLen + 1)
                'loop through the array
                For A = StartPos To UBound(ByteArray) - KeyLen - 1 Step 2
                    TempByte = ByteArray(A)
                    TempByte2 = ByteArray(A + 1)
                    If (TempByte = FirstKeyByte Or TempByte = FirstKeyByteU) And (TempByte2 = FirstKeyByte2 Or TempByte2 = FirstKeyByte2U) Then
                        TempByte = ByteArray(A + KeyLen)
                        TempByte2 = ByteArray(A + KeyLen + 1)
                        If (TempByte = LastKeyByte Or TempByte = LastKeyByteU) And (TempByte2 = LastKeyByte2 Or TempByte2 = LastKeyByte2U) Then
                            If KeyLen > 4 Then
                                'check if keyword is found from the array
                                C = A + 2
                                For B = 2 To KeyLen - 1 Step 2
                                    TempByte = ByteArray(C)
                                    TempByte2 = ByteArray(C + 1)
                                    If Not ((TempByte = KeyBuffer(B) Or TempByte = KeyBufferU(B)) And (TempByte2 = KeyBuffer(B + 1) Or TempByte2 = KeyBufferU(B + 1))) Then Exit For
                                    C = C + 2
                                Next B
                                'keyword is found!
                                If B >= KeyLen Then
                                    InBArr = A
                                    Exit Function
                                End If
                            Else
                                InBArr = A
                                Exit Function
                            End If
                        End If
                    End If
                Next A
            End If
        Else
            If StartPos > UBound(ByteArray) - KeyUpper Then StartPos = UBound(ByteArray) - KeyUpper
            FirstKeyByte = KeyBuffer(0)
            LastKeyByte = KeyBuffer(KeyLen)
            If Compare = vbBinaryCompare Then
                'loop through the array
                For A = StartPos To UBound(ByteArray) - KeyUpper
                    If ByteArray(A) = FirstKeyByte Then
                        If ByteArray(A + KeyUpper) = LastKeyByte Then
                            If KeyLen > 4 Then
                                'check if keyword is found from the array
                                C = A + 1
                                For B = 2 To KeyLen Step 2
                                    If Not (ByteArray(C) = KeyBuffer(B)) Then Exit For
                                    C = C + 1
                                Next B
                                'keyword is found!
                                If B > KeyLen Then
                                    InBArr = A
                                    Exit Function
                                End If
                            Else
                                InBArr = A
                                Exit Function
                            End If
                        End If
                    End If
                Next A
            Else 'vbTextCompare
                FirstKeyByteU = KeyBufferU(0)
                LastKeyByteU = KeyBufferU(KeyLen)
                'loop through the array
                For A = StartPos To UBound(ByteArray) - KeyUpper
                    TempByte = ByteArray(A)
                    If TempByte = FirstKeyByte Or TempByte = FirstKeyByteU Then
                        TempByte = ByteArray(A + KeyUpper)
                        If TempByte = LastKeyByte Or TempByte = LastKeyByteU Then
                            If KeyLen > 4 Then
                                'check if keyword is found from the array
                                C = A + 1
                                For B = 2 To KeyLen Step 2
                                    TempByte = ByteArray(C)
                                    If Not (TempByte = KeyBuffer(B) Or TempByte = KeyBufferU(B)) Then Exit For
                                    C = C + 1
                                Next B
                                'keyword is found!
                                If B > KeyLen Then
                                    InBArr = A
                                    Exit Function
                                End If
                            Else
                                InBArr = A
                                Exit Function
                            End If
                        End If
                    End If
                Next A
            End If
        End If
        InBArr = -1
    End Function
    It can now handle both ANSI and Unicode byte arrays and it is 100% valid in Unicode mode (note that it can't process ligatures, they're quite bothersome to code support for).

  21. #21

    Thread Starter
    Fanatic Member aconybeare's Avatar
    Join Date
    Oct 2001
    Location
    UK
    Posts
    772

    Re: instr Count

    Merri,

    Nice one, I think I must be doing something wrong, I'm testing it using this -
    VB Code:
    1. Dim fFailed As Boolean
    2. If InBArr(StrConv("a[HL="#FFFF00"]b[/HL]c", vbFromUnicode), "b") <> 1 Then Stop: fFailed = True

    I'm getting -1 back when I'm expecting it to return 1??

    Any ideas?

    Cheers Al

  22. #22
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: instr Count

    You don't need to use StrConv. It is now Unicode-aware. It will return 2, because a character is two bytes.

    VB Code:
    1. ' Unicode:
    2. If InBArr("abc", "b") <> 2 Then Stop: fFailed = True
    3.  
    4. ' ANSI:
    5. If InBArr(StrConv("abc", vbFromUnicode), "b", , ,False) <> 1 Then Stop: fFailed = True

  23. #23

    Thread Starter
    Fanatic Member aconybeare's Avatar
    Join Date
    Oct 2001
    Location
    UK
    Posts
    772

    Re: instr Count

    Merri,

    This one is failing am I doing something wrong?

    VB Code:
    1. If InBArr(StrConv("abab", vbFromUnicode), "ab", 3, , False) <> 0 Then Stop: fFailed = True


    Doesn't seem to recognise the start position, although it's returning 2 so maybe I need to pass it 6 in order to get the correct result, Is that correct?

    No that didn't work?

    Al
    Last edited by aconybeare; Jul 8th, 2005 at 06:50 AM.

  24. #24
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: instr Count

    You should have -1 there, not 0

    Edit Uh, that of course just by looking at the code, not the comment. Humm... probably an error in the ANSI part of the code. If you try it in Unicode, it should work fine. I haven't validated the ANSI part of the code.
    Last edited by Merri; Jul 8th, 2005 at 07:27 AM.

  25. #25

    Thread Starter
    Fanatic Member aconybeare's Avatar
    Join Date
    Oct 2001
    Location
    UK
    Posts
    772

    Re: instr Count

    When I try running it in uni mode I get the following error -

    Compile Error:
    Typemismatch: Array or user defined type expected


    here is my call -

    VB Code:
    1. If InBArr("abc", "b") <> 2 Then Stop: fFailed = True

  26. #26
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: instr Count

    Oops, my mistake in the example code there. Should've been:

    VB Code:
    1. Dim Temp() As Byte
    2.  
    3. Temp = "abab"
    4. If InBArr(Temp, "b") <> 2 Then Stop: fFailed = True


    Here is a complete test code so you don't need to bother as much with the Unicode side of the code. I'm fixing the ANSI side atm.

    VB Code:
    1. Public Function IsGoodInBArr(Optional fLigaturesToo As Boolean) As Boolean
    2. ' verify correct InStr returns, 20021005
    3. ' returns True if all tests are passed
    4.   Dim fFailed As Boolean
    5.   Dim Temp() As Byte
    6.   Dim Test As Long
    7.  
    8.   ' replace ".InStr01" with the name of your function
    9.   Temp = "abc"
    10.   If InBArr(Temp, "b") <> 2 Then Stop: fFailed = True
    11.   Temp = "abab"
    12.   If InBArr(Temp, "ab") <> 0 Then Stop: fFailed = True
    13.   Temp = "abab"
    14.   If InBArr(Temp, "aB") <> -1 Then Stop: fFailed = True
    15.   Temp = "abab"
    16.   If InBArr(Temp, "aB", , vbTextCompare) <> 0 Then Stop: fFailed = True
    17.   Temp = "abab"
    18.   If InBArr(Temp, "ab", 2) <> 4 Then Stop: fFailed = True
    19.   Temp = "abab"
    20.   If InBArr(Temp, "ab", 4) <> 4 Then Stop: fFailed = True
    21.   Temp = "abab"
    22.   If InBArr(Temp, "ab", 6) <> -1 Then Stop: fFailed = True
    23.   Temp = "aaabcab"
    24.   If InBArr(Temp, "abc", 6) <> -1 Then Stop: fFailed = True
    25.   Temp = "abab"
    26.   If InBArr(Temp, "", 6) <> 6 Then Stop: fFailed = True
    27.   Temp = "abab"
    28.   If InBArr(Temp, "", 8) <> 8 Then Stop: fFailed = True
    29.   Erase Temp
    30.   If InBArr(Temp, "", 6) <> -1 Then Stop: fFailed = True
    31.   Temp = "abab"
    32.   If InBArr(Temp, "c") <> -1 Then Stop: fFailed = True
    33.  
    34.   Temp = "abcdabcd"
    35.   If InBArr(Temp, "abcd") <> 0 Then Stop: fFailed = True
    36.   Temp = "abab"
    37.   If InBArr(Temp, "Ab") <> -1 Then Stop: fFailed = True
    38.   Temp = "abab"
    39.   If InBArr(Temp, "Ab", , vbTextCompare) <> 0 Then Stop: fFailed = True
    40.  
    41.   Temp = "a" & String$(50000, "b")
    42.   If InBArr(Temp, "a") <> 0 Then Stop: fFailed = True
    43.  
    44.   ' unicode
    45.   Temp = "a€€c"
    46.   If InBArr(Temp, "€") <> 2 Then Stop: fFailed = True
    47.  
    48.   ' the 4 stooges: š/Š, œ/Œ, ž/Ž, ÿ/Ÿ (154/138, 156/140, 158/142, 255/159)
    49.   Temp = "Hašiš"
    50.   If InBArr(Temp, "Š", , vbTextCompare) <> 4 Then Stop: fFailed = True
    51.   ' ligatures  textcompare (VBspeed entries do NOT have to pass this test)
    52.   If fLigaturesToo Then
    53.     ' ligatures, a digraphemic fun house: ss/ß, ae/æ, oe/œ, th/þ
    54.     Temp = "Straße"
    55.     If InBArr(Temp, "ss", , vbTextCompare) <> 8 Then Stop: fFailed = True
    56.   End If
    57.  
    58.   ' well done
    59.   IsGoodInBArr = Not fFailed
    60.  
    61. End Function


    Edit Found the error, it is in both ANSI and Unicode, but there was a second bug in the Unicode mode which prevented it from causing an error. I'll work out the InBArrRev now...
    Last edited by Merri; Jul 8th, 2005 at 07:57 AM.

  27. #27
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: instr Count

    Here is a fresh test project. Try and see if there are any problems
    Attached Files Attached Files

  28. #28

    Thread Starter
    Fanatic Member aconybeare's Avatar
    Join Date
    Oct 2001
    Location
    UK
    Posts
    772

    Re: instr Count

    Excellent!

    These are my test results -

    VB Code:
    1. InBArray,      InStr,   InTheStr
    2. TextCompare - [HL="#FFFF00"]642[/HL],       7610,     4196
    3. BinaryCompare-349,        [HL="#FFFF00"]4[/HL],       4540
    If you can do binary search then InStr is like lightening
    but with textCompare InBArr rules

    Obviously this is just one check I'll need to do more thorough testing to get a better idea of it's overall capabilities,

    InBRev is very, very slow with both BinaryCompare and TextCompare

  29. #29
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: instr Count

    You have to note InTheString support only BinaryCompare. Also, InBArrRev should be as fast as InBArr, just searching to opposite direction (from end to beginning)? I get 5 ms vs. 50 ms when I compare InBArrRev to InStrRev with the test file I have.


    By using a bigger test file you should get much more accurate test results... at the moment it mainly tests for multiple calls of the function.

  30. #30
    I'm about to be a PowerPoster!
    Join Date
    Jan 2005
    Location
    Everywhere
    Posts
    13,647

    Re: instr Count

    Merri, the declaration of lstrlenW in your project was wrong... It should be ByVal, not ByRef... which is why you are always getting 5 (in the other thread). I fixed that and ran my original InTheString function, and also made a new one which is a fair bit faster (but nowhere near InStr.)

    Here is the results:

    Code:
    Results (Binary Compare):
    
    InStr:            68 ms: 49533
    InTheString2:   8556 ms: 49533
    InBArr:         9135 ms: 49532  <-- Out by one
    InTheString:    9806 ms: 49533
    And my InTheString and InTheString2 functions::

    Code:
    Public Function InTheString(ByVal lpszStringToSearch As Long, _
                                ByVal lpszSearchFor As Long, _
                                Optional ByVal plngStartPos As Long = 1 _
                               ) As Long
    
    Dim charBuffer()    As Byte
    Dim charSearchFor() As Byte
    Dim lngStringLen    As Long
    Dim lngString2Len   As Long
    Dim lpbSearchFor    As Long
    Dim i               As Long
        
        lngStringLen = lstrlenW(lpszStringToSearch) * 2
        lngString2Len = lstrlenW(lpszSearchFor) * 2
            
        ReDim charBuffer(lngStringLen - 1)
        ReDim charSearchFor(lngString2Len - 1)
        
        lpbSearchFor = VarPtr(charSearchFor(0))
        
        RtlMoveMemory charBuffer(0), _
                      ByVal lpszStringToSearch, _
                      lngStringLen - 1
        
        RtlMoveMemory ByVal lpbSearchFor, _
                      ByVal lpszSearchFor, _
                      lngString2Len - 1
        
        If (lngString2Len < lngStringLen) Then
            For i = (plngStartPos - 1) To (lngStringLen - lngString2Len) Step 2
                If (RtlCompareMemory(charBuffer(i), _
                                     ByVal lpbSearchFor, _
                                     lngString2Len _
                                    ) = lngString2Len) Then
                    InTheString = (i \ 2) + plngStartPos
                    Exit Function
                End If
            Next i
        End If
    
        InTheString = -1
    End Function
    
    
    Public Function InTheString2(ByVal lpszStringToSearch As Long, _
                                 ByVal lpszSearchFor As Long, _
                                 Optional ByVal plngStartPos As Long = 1 _
                                ) As Long
    
    Dim charBuffer()    As Byte
    Dim charSearchFor() As Byte
    Dim lngStringLen    As Long
    Dim lngString2Len   As Long
    Dim lpbSearchFor    As Long
    Dim i               As Long
    Dim j               As Long
        
        lngStringLen = lstrlenW(lpszStringToSearch) * 2
        lngString2Len = lstrlenW(lpszSearchFor) * 2
            
        ReDim charBuffer(lngStringLen - 1)
        ReDim charSearchFor(lngString2Len - 1)
        
        lpbSearchFor = VarPtr(charSearchFor(0))
        
        RtlMoveMemory charBuffer(0), _
                      ByVal lpszStringToSearch, _
                      lngStringLen - 1
        
        RtlMoveMemory ByVal lpbSearchFor, _
                      ByVal lpszSearchFor, _
                      lngString2Len - 1
        
        If (lngString2Len < lngStringLen) Then
            For i = (plngStartPos - 1) To (lngStringLen - lngString2Len) Step 2
                Do While (charBuffer(i + j) = charSearchFor(j))
                    If j + 1 = UBound(charSearchFor) Then
                        InTheString2 = (i \ 2) + 1
                        Exit Function
                    End If
                    j = j + 2
                Loop
                j = 0
            Next i
        End If
    
        InTheString2 = -1
    End Function
    The test keyword I used was "ZwNotifyChangeKey" and the test file (dumpbin on ntdll.dll) is attached:
    Attached Files Attached Files

  31. #31
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: instr Count

    A few things to think about

    1) InBArr returns a byte position in the array, it is meant to be off by one (strings start from 1, byte arrays start from 0).
    2) You apparently didn't compile your program with all advanced optimizations?
    3) My code gets slower with a lot of data; I can optimize it with an API call, but it is bothersome only with bigger keywords. I don't know yet what is the critical length.
    4) You should consider using SAFEARRAY instead of RtlMoveMemory... that way you could pass strings ByRef to the function and also gain a speed up. I wanted to use native VB6 code in InBArr to show how much you can really do with it.
    5) You didn't post the benchmark code, always appreciated when doing something with it.
    6) Your code is actually only six times slower than InStr when compiled. Mine is four times slower (binary mode). Result varies with input data though, I haven't done a proper test with a huge file.
    7) Your code doesn't support TextCompare, which is one the main needs; it is often tried to be skipped only because InStr is very slow in TextCompare mode.


    Edit I tried your bigger file to do some testing... some results:
    InBArr, BinaryCompare: 326 ms
    InStr, BinaryCompare: 78 ms
    InTheString2: 450 ms

    InBArr, TextCompare: 275 ms (!!!)
    InStr, TextCompare: 1111 ms

    Each one reported the correct position.


    Edit #2 I'm now making some further small changes to the code now that I found a way to optimize a bit...
    Last edited by Merri; Jul 8th, 2005 at 02:55 PM.

  32. #32
    I'm about to be a PowerPoster!
    Join Date
    Jan 2005
    Location
    Everywhere
    Posts
    13,647

    Re: instr Count

    Quote Originally Posted by Merri
    1) InBArr returns a byte position in the array, it is meant to be off by one (strings start from 1, byte arrays start from 0).
    Then it is returning an offset, not a position

    2) You apparently didn't compile your program with all advanced optimizations?
    No, it was 4 am, and I ran it from the IDE

    4) You should consider using SAFEARRAY instead of RtlMoveMemory... that way you could pass strings ByRef to the function and also gain a speed up. I wanted to use native VB6 code in InBArr to show how much you can really do with it.
    I'm not sure what you mean. All VB arrays are actually SAFEARRAYs, I'm merely using RtlMoveMemory to shift the string into the data buffer part of one. I could also use RtlCompareMemory on the string itself, to save using any byte arrays, but that would result in more API calls which would probably slow it down.

    5) You didn't post the benchmark code, always appreciated when doing something with it.
    I used yours

    7) Your code doesn't support TextCompare, which is one the main needs; it is often tried to be skipped only because InStr is very slow in TextCompare mode.
    Added, in a new function

    I'll post the new function when I have it fixed. It doesn't use any API's and is just slightly slower that yours in binary compare mode. Also it incorporates a benchmarking cheat, it checks each time whether the parameters are the same and if they are then it returns the result it found last time. Doing that I was able to achieve 1 ms for the benchmark But it can be commented out.

  33. #33
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: instr Count

    Quote Originally Posted by penagate
    Then it is returning an offset, not a position
    Think about it: it is meant to give a position in the array. Not in a string. InBArr is the name and it is much easier to get the correct position value you are using when working with byte arrays. I wasn't making a replacement for InStr, I made a new function to use with byte arrays (because handling byte arrays is faster and there aren't any functions you can use to handle byte arrays).

    Quote Originally Posted by penagate
    I'm not sure what you mean. All VB arrays are actually SAFEARRAYs
    Take a look at VBspeed: http://www.xbeat.net/vbspeed/i_Dope.htm#modules

    Quote Originally Posted by penagate
    Also it incorporates a benchmarking cheat, it checks each time whether the parameters are the same and if they are then it returns the result it found last time. Doing that I was able to achieve 1 ms for the benchmark But it can be commented out.
    I had a cheat before, but it broke the function from working properly (I used StrPtr). It seemed to give back an invalid, old value, so it used an old keyword when a keyword changed. 1 ms here or there isn't much.

    Here is the new InBArr and InBArrRev... they are both a "bit" faster now (80 ms faster!).

    CODE IN NEXT POST BECAUSE IT DIDN'T FIT HERE

    Last test with this code:
    InBArr, vbBinaryCompare: 221 ms (InStr 79 ms)
    InBArr, vbTextCompare: 312 ms

    InBArrRev, vbBinaryCompare: 70 ms (InStrRev 190 ms)
    InBArrRev, vbTextCompare: 78 ms

  34. #34
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: instr Count

    Code:
    Option Explicit
    Public Function InBArr(ByRef ByteArray() As Byte, ByRef KeyWord As String, Optional StartPos As Long = 0, Optional Compare As Byte = vbBinaryCompare, Optional IsUnicode As Boolean = True) As Long
        Static KeyBuffer() As Byte, KeyBufferU() As Byte
        Dim A As Long, B As Long, C As Long, KeyLen As Long, KeyUpper As Long
        Dim FirstKeyByte As Byte, LastKeyByte As Byte, TempByte As Byte
        Dim FirstKeyByte2 As Byte, LastKeyByte2 As Byte, TempByte2 As Byte
        Dim FirstKeyByteU As Byte, LastKeyByteU As Byte
        Dim FirstKeyByte2U As Byte, LastKeyByte2U As Byte
        If (Not ByteArray) = True Then InBArr = -1: Exit Function
        If LenB(KeyWord) = 0 Then InBArr = StartPos: Exit Function
        If Compare = vbBinaryCompare Then
            KeyBuffer = KeyWord
        Else
            KeyBufferU = UCase$(KeyWord)
            KeyBuffer = LCase$(KeyWord)
        End If
        KeyLen = UBound(KeyBuffer) - 1
        If StartPos < 0 Then StartPos = 0
        If IsUnicode Then
            If KeyLen > UBound(ByteArray) - 1 Then InBArr = -1: Exit Function
            If (StartPos Mod 2) = 1 Then StartPos = StartPos - (StartPos Mod 2) + 2
            If StartPos > UBound(ByteArray) - KeyLen Then InBArr = -1: Exit Function
            FirstKeyByte = KeyBuffer(0)
            LastKeyByte = KeyBuffer(KeyLen)
            FirstKeyByte2 = KeyBuffer(1)
            LastKeyByte2 = KeyBuffer(KeyLen + 1)
            If Compare = vbBinaryCompare Then
                'loop through the array
                For A = StartPos To UBound(ByteArray) - KeyLen - 1 Step 2
                    TempByte = ByteArray(A)
                    TempByte2 = ByteArray(A + 1)
                    If TempByte = FirstKeyByte And TempByte2 = FirstKeyByte2 Then
                        TempByte = ByteArray(A + KeyLen)
                        TempByte2 = ByteArray(A + KeyLen + 1)
                        If TempByte = LastKeyByte And TempByte2 = LastKeyByte2 Then
                            If KeyLen > 4 Then
                                'check if keyword is found from the array
                                C = A + 2
                                For B = 2 To KeyLen - 1 Step 2
                                    If Not (ByteArray(C) = KeyBuffer(B) And ByteArray(C + 1) = CByte(KeyBuffer(B + 1))) Then Exit For
                                    C = C + 2
                                Next B
                                'keyword is found!
                                If B >= KeyLen Then
                                    InBArr = A
                                    Exit Function
                                End If
                            Else
                                InBArr = A
                                Exit Function
                            End If
                        End If
                    End If
                Next A
            Else 'vbTextCompare
                FirstKeyByteU = KeyBufferU(0)
                LastKeyByteU = KeyBufferU(KeyLen)
                FirstKeyByte2U = KeyBufferU(1)
                LastKeyByte2U = KeyBufferU(KeyLen + 1)
                'loop through the array
                For A = StartPos To UBound(ByteArray) - KeyLen - 1 Step 2
                    TempByte = ByteArray(A)
                    TempByte2 = ByteArray(A + 1)
                    If (TempByte = FirstKeyByte Or TempByte = FirstKeyByteU) And (TempByte2 = FirstKeyByte2 Or TempByte2 = FirstKeyByte2U) Then
                        TempByte = ByteArray(A + KeyLen)
                        TempByte2 = ByteArray(A + KeyLen + 1)
                        If (TempByte = LastKeyByte Or TempByte = LastKeyByteU) And (TempByte2 = LastKeyByte2 Or TempByte2 = LastKeyByte2U) Then
                            If KeyLen > 4 Then
                                'check if keyword is found from the array
                                C = A + 2
                                For B = 2 To KeyLen - 1 Step 2
                                    TempByte = ByteArray(C)
                                    TempByte2 = ByteArray(C + 1)
                                    If Not ((TempByte = KeyBuffer(B) Or TempByte = KeyBufferU(B)) And (TempByte2 = KeyBuffer(B + 1) Or TempByte2 = KeyBufferU(B + 1))) Then Exit For
                                    C = C + 2
                                Next B
                                'keyword is found!
                                If B >= KeyLen Then
                                    InBArr = A
                                    Exit Function
                                End If
                            Else
                                InBArr = A
                                Exit Function
                            End If
                        End If
                    End If
                Next A
            End If
        Else
            KeyUpper = KeyLen \ 2
            If KeyUpper > UBound(ByteArray) Then InBArr = -1: Exit Function
            If StartPos > UBound(ByteArray) - KeyUpper Then InBArr = -1: Exit Function
            FirstKeyByte = KeyBuffer(0)
            LastKeyByte = KeyBuffer(KeyLen)
            If Compare = vbBinaryCompare Then
                'loop through the array
                Debug.Print StartPos
                For A = StartPos To UBound(ByteArray) - KeyUpper
                    If ByteArray(A) = FirstKeyByte Then
                        If ByteArray(A + KeyUpper) = LastKeyByte Then
                            If KeyLen > 4 Then
                                'check if keyword is found from the array
                                C = A + 1
                                For B = 2 To KeyLen Step 2
                                    If Not (ByteArray(C) = KeyBuffer(B)) Then Exit For
                                    C = C + 1
                                Next B
                                'keyword is found!
                                If B > KeyLen Then
                                    InBArr = A
                                    Exit Function
                                End If
                            Else
                                InBArr = A
                                Exit Function
                            End If
                        End If
                    End If
                Next A
            Else 'vbTextCompare
                FirstKeyByteU = KeyBufferU(0)
                LastKeyByteU = KeyBufferU(KeyLen)
                'loop through the array
                For A = StartPos To UBound(ByteArray) - KeyUpper
                    TempByte = ByteArray(A)
                    If TempByte = FirstKeyByte Or TempByte = FirstKeyByteU Then
                        TempByte = ByteArray(A + KeyUpper)
                        If TempByte = LastKeyByte Or TempByte = LastKeyByteU Then
                            If KeyLen > 4 Then
                                'check if keyword is found from the array
                                C = A + 1
                                For B = 2 To KeyLen Step 2
                                    TempByte = ByteArray(C)
                                    If Not (TempByte = KeyBuffer(B) Or TempByte = KeyBufferU(B)) Then Exit For
                                    C = C + 1
                                Next B
                                'keyword is found!
                                If B > KeyLen Then
                                    InBArr = A
                                    Exit Function
                                End If
                            Else
                                InBArr = A
                                Exit Function
                            End If
                        End If
                    End If
                Next A
            End If
        End If
        InBArr = -1
    End Function
    *sniff* Wished I could post longer posts.

  35. #35
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: instr Count

    Code:
    Public Function InBArrRev(ByRef ByteArray() As Byte, ByRef KeyWord As String, Optional StartPos As Long = -1, Optional Compare As Byte = vbBinaryCompare, Optional IsUnicode As Boolean = True) As Long
        Static KeyBuffer() As Byte, KeyBufferU() As Byte
        Dim A As Long, B As Long, C As Long, KeyLen As Long, KeyUpper As Long
        Dim FirstKeyByte As Byte, LastKeyByte As Byte, TempByte As Byte
        Dim FirstKeyByte2 As Byte, LastKeyByte2 As Byte, TempByte2 As Byte
        Dim FirstKeyByteU As Byte, LastKeyByteU As Byte
        Dim FirstKeyByte2U As Byte, LastKeyByte2U As Byte
        If (Not ByteArray) = True Then InBArrRev = -1: Exit Function
        If LenB(KeyWord) = 0 Then InBArrRev = StartPos: Exit Function
        If Compare = vbBinaryCompare Then
            KeyBuffer = KeyWord
        Else
            KeyBufferU = UCase$(KeyWord)
            KeyBuffer = LCase$(KeyWord)
        End If
        KeyLen = UBound(KeyBuffer) - 1
        If IsUnicode Then
            If KeyLen > UBound(ByteArray) - 1 Then InBArrRev = -1: Exit Function
            If StartPos < 0 Then StartPos = UBound(ByteArray) - KeyLen - 1
            If (StartPos Mod 2) = 1 Then StartPos = StartPos - (StartPos Mod 2) + 2
            If StartPos >= UBound(ByteArray) - KeyLen Then InBArrRev = -1: Exit Function
            FirstKeyByte = KeyBuffer(0)
            LastKeyByte = KeyBuffer(KeyLen)
            FirstKeyByte2 = KeyBuffer(1)
            LastKeyByte2 = KeyBuffer(KeyLen + 1)
            If Compare = vbBinaryCompare Then
                'loop through the array
                For A = StartPos To 0 Step -2
                    TempByte = ByteArray(A)
                    TempByte2 = ByteArray(A + 1)
                    If TempByte = FirstKeyByte And TempByte2 = FirstKeyByte2 Then
                        TempByte = ByteArray(A + KeyLen)
                        TempByte2 = ByteArray(A + KeyLen + 1)
                        If TempByte = LastKeyByte And TempByte2 = LastKeyByte2 Then
                            If KeyLen > 4 Then
                                'check if keyword is found from the array
                                C = A + 2
                                For B = 2 To KeyLen - 1 Step 2
                                    If Not (ByteArray(C) = KeyBuffer(B) And ByteArray(C + 1) = KeyBuffer(B + 1)) Then Exit For
                                    C = C + 2
                                Next B
                                'keyword is found!
                                If B >= KeyLen Then
                                    InBArrRev = A
                                    Exit Function
                                End If
                            Else
                                InBArrRev = A
                                Exit Function
                            End If
                        End If
                    End If
                Next A
            Else 'vbTextCompare
                FirstKeyByteU = KeyBufferU(0)
                LastKeyByteU = KeyBufferU(KeyLen)
                FirstKeyByte2U = KeyBufferU(1)
                LastKeyByte2U = KeyBufferU(KeyLen + 1)
                'loop through the array
                For A = StartPos To 0 Step -2
                    TempByte = ByteArray(A)
                    TempByte2 = ByteArray(A + 1)
                    If (TempByte = FirstKeyByte Or TempByte = FirstKeyByteU) And (TempByte2 = FirstKeyByte2 Or TempByte2 = FirstKeyByte2U) Then
                        TempByte = ByteArray(A + KeyLen)
                        TempByte2 = ByteArray(A + KeyLen + 1)
                        If (TempByte = LastKeyByte Or TempByte = LastKeyByteU) And (TempByte2 = LastKeyByte2 Or TempByte2 = LastKeyByte2U) Then
                            If KeyLen > 4 Then
                                'check if keyword is found from the array
                                C = A + 2
                                For B = 2 To KeyLen - 1 Step 2
                                    TempByte = ByteArray(C)
                                    TempByte2 = ByteArray(C + 1)
                                    If Not ((TempByte = KeyBuffer(B) Or TempByte = KeyBufferU(B)) And (TempByte2 = KeyBuffer(B + 1) Or TempByte2 = KeyBufferU(B + 1))) Then Exit For
                                    C = C + 2
                                Next B
                                'keyword is found!
                                If B >= KeyLen Then
                                    InBArrRev = A
                                    Exit Function
                                End If
                            Else
                                InBArrRev = A
                                Exit Function
                            End If
                        End If
                    End If
                Next A
            End If
        Else
            KeyUpper = KeyLen \ 2
            If KeyUpper > UBound(ByteArray) Then InBArrRev = -1: Exit Function
            If StartPos < 0 Then StartPos = UBound(ByteArray) - KeyUpper
            If StartPos > UBound(ByteArray) - KeyUpper Then InBArrRev = -1: Exit Function
            FirstKeyByte = KeyBuffer(0)
            LastKeyByte = KeyBuffer(KeyLen)
            If Compare = vbBinaryCompare Then
                'loop through the array
                Debug.Print StartPos
                For A = StartPos To 0 Step -1
                    If ByteArray(A) = FirstKeyByte Then
                        If ByteArray(A + KeyUpper) = LastKeyByte Then
                            If KeyLen > 4 Then
                                'check if keyword is found from the array
                                C = A + 1
                                For B = 2 To KeyLen Step 2
                                    If Not (ByteArray(C) = KeyBuffer(B)) Then Exit For
                                    C = C + 1
                                Next B
                                'keyword is found!
                                If B > KeyLen Then
                                    InBArrRev = A
                                    Exit Function
                                End If
                            Else
                                InBArrRev = A
                                Exit Function
                            End If
                        End If
                    End If
                Next A
            Else 'vbTextCompare
                FirstKeyByteU = KeyBufferU(0)
                LastKeyByteU = KeyBufferU(KeyLen)
                'loop through the array
                For A = StartPos To 0 Step -1
                    TempByte = ByteArray(A)
                    If TempByte = FirstKeyByte Or TempByte = FirstKeyByteU Then
                        TempByte = ByteArray(A + KeyUpper)
                        If TempByte = LastKeyByte Or TempByte = LastKeyByteU Then
                            If KeyLen > 4 Then
                                'check if keyword is found from the array
                                C = A + 1
                                For B = 2 To KeyLen Step 2
                                    TempByte = ByteArray(C)
                                    If Not (TempByte = KeyBuffer(B) Or TempByte = KeyBufferU(B)) Then Exit For
                                    C = C + 1
                                Next B
                                'keyword is found!
                                If B > KeyLen Then
                                    InBArrRev = A
                                    Exit Function
                                End If
                            Else
                                InBArrRev = A
                                Exit Function
                            End If
                        End If
                    End If
                Next A
            End If
        End If
        InBArrRev = -1
    End Function

  36. #36
    I'm about to be a PowerPoster!
    Join Date
    Jan 2005
    Location
    Everywhere
    Posts
    13,647

    Re: instr Count

    Quote Originally Posted by Merri
    I had a cheat before, but it broke the function from working properly (I used StrPtr). It seemed to give back an invalid, old value, so it used an old keyword when a keyword changed. 1 ms here or there isn't much.
    I had that problem but fixed it now. The essence of mine is the same as yours.

    I used static variables to hold the last paramaters (pointer to string to search, pointer to keyword string, starting pos, compare method, Unicode/ANSI) and at the start of the function it checks to see if any of those has changed. If they have it re-loops through the string, otherwise it just spits back the last result (also held in a static).

  37. #37
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: instr Count

    Er... you don't check if a contents in the string have changed? Because StrPtr might not change even though string contents change. You have to loop through, cheating that much gives both invalid results in real use and gives false information about the speed of the function. Also, I did those other checks, but that doesn't change the fact that StrPtr sometimes gives invalid results. So I got rid of the check and got the 1 ms or so extra. Doesn't hurt too much.

    I thought about making Keyword an optional parameter, so the coder could optimize the speed that way. So keyword could stay the same.
    Last edited by Merri; Jul 9th, 2005 at 01:55 PM.

  38. #38
    I'm about to be a PowerPoster!
    Join Date
    Jan 2005
    Location
    Everywhere
    Posts
    13,647

    Re: instr Count

    No, if you change the string between 2 subsequent calls the pointer will have changed. Unless both of your strings go out of scope and VB allocates a new string to the original. I didn't think of that. I suppose you could test a combination of VarPtr and StrPtr.

  39. #39
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: instr Count

    But think about it: it is possible to change contents of a string with CopyMemory for example. The pointer doesn't change in that case. Or someone can use an external ASM library which does something and the pointer doesn't change.

  40. #40

    Thread Starter
    Fanatic Member aconybeare's Avatar
    Join Date
    Oct 2001
    Location
    UK
    Posts
    772

    Re: instr Count

    Merri,

    I have what is probably a dumb question but I'm going to ask it anyway -

    If the user has opted for vbTextCompare why don't you just lCase the string then do binary compare as normal? This would cut out a big chunk of your code guess the trade off would would mean passing the buffer byVal as opposed to byRef?


    Hmmm probably because doing a binary array check is so slow

    Al
    Last edited by aconybeare; Jul 11th, 2005 at 05:32 AM.

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width