VBspeed / String / WordCount
VBspeed © 2000-10, updated: 28-Nov-2001
WordCount


Function WordCount
Counts the words found within a given text string. Surprised? Now, what's a word? Words are delimited by white space. What's white space? Blanks, tabs, carriage returns, line feeds, nullchars, etc... Let's keep it simple: white space is ASCII 0 thru 32.
  Function WordCount(ByRef sText As String) As Long
  
  WordCount("")                 --> 0
  WordCount("word")             --> 1
  WordCount("wordword")         --> 1
  WordCount(".word.word.")      --> 1
  WordCount("word word")        --> 2
  WordCount(" word word ")      --> 2
  WordCount("  word  word  ")   --> 2
  WordCount("a" & vbCrLf & "B") --> 2
Code
WordCount01
Public Function WordCount01(ByRef sText As String) As Long
' by Chris Lucas, cdl1051@earthlink.net, 20011113
    Dim dest() As Byte
    Dim i As Long

    If LenB(sText) Then
        ' Move the string's byte array into dest()
        ReDim dest(LenB(sText))
        CopyMemory dest(0), ByVal StrPtr(sText), LenB(sText) - 1

        ' Now loop through the array and count the words
        For i = 0 To UBound(dest) Step 2
            If dest(i) > 32 Then
                 Do Until dest(i) < 33
                    i = i + 2
                 Loop
                 WordCount01 = WordCount01 + 1
            End If
        Next i
        Erase dest
    Else
        ' This is easy eh?
        WordCount01 = 0
    End If

End Function
WordCount02
Public Function WordCount02(ByRef sText As String) As Long
' by Chris Lucas, cdl1051@earthlink.net, 20011115
    Dim dest() As Byte
    Dim i As Long
    Dim tmpCount As Long
    
    If LenB(sText) Then
        ReDim dest(LenB(sText))
        CopyMemory dest(0), ByVal StrPtr(sText), LenB(sText) - 1
        For i = 0 To UBound(dest) Step 2
            If dest(i) > 32 Then
                Do Until dest(i) < 33
                   i = i + 2
                Loop
                tmpCount = tmpCount + 1
            End If
        Next i
        Erase dest
    End If
    WordCount02 = tmpCount
End Function
WordCount03
Public Function WordCount03(ByRef sText As String) As Long
' by Donald, donald@xbeat.net, 20011114
' based on WordCount01 by Chris
  Const cCharLow As Byte = 33
  Dim abText() As Byte
  Dim i As Long
  
  If LenB(sText) Then
    ReDim abText(LenB(sText))
    CopyMemory abText(0), ByVal StrPtr(sText), LenB(sText) - 1
    For i = 0 To UBound(abText) Step 2
      If abText(i) >= cCharLow Then
        Do
          i = i + 2
        Loop Until abText(i) < cCharLow
        WordCount03 = WordCount03 + 1
      End If
    Next
  End If

End Function
WordCount04
Public Function WordCount04(ByRef sText As String) As Long
' by Donald, donald@xbeat.net, 20011114
  Dim cCharLow As Byte: cCharLow = 33
  Dim abText() As Byte
  Dim i As Long
  
  If LenB(sText) Then
    ReDim abText(LenB(sText))
    CopyMemory abText(0), ByVal StrPtr(sText), LenB(sText) - 1
    For i = 0 To UBound(abText) Step 2
      If abText(i) >= cCharLow Then
        Do
          i = i + 2
        Loop Until abText(i) < cCharLow
        WordCount04 = WordCount04 + 1
      End If
    Next
  End If

End Function
WordCount05
Public Function WordCount05(ByRef sText As String) As Long
  ' by Paul - wpsjr1@syix.com, 20011117
  ' based on code from Don and Chris
  ' doping - string.tlb
  Dim a() As Byte
  Static b() As Byte
  Dim cCharLow As Byte: cCharLow = 33
  Dim lLen As Long
  Static lPrevLen As Long
  Dim i As Long
  
  lLen = LenB(sText)
  If lLen Then
    If lLen > 100 And lLen < 100000 Then
      ReDim a(lLen) ' faster to blindly redim than check
      CopyMemory a(0), ByVal StrPtr(sText), lLen
      For i = 0 To lLen - 1 Step 2
        If a(i) >= cCharLow Then
          Do
            i = i + 2
          Loop Until a(i) < cCharLow
          WordCount05 = WordCount05 + 1
        End If
      Next
    Else
      lLen = lLen \ 2
      If lPrevLen <> lLen Then ' only redim when necessary
        ReDim b(lLen)
        lPrevLen = lLen
      End If
      FastString.WideCharToMultiByte 0&, 0&, sText, lLen, b(0), lLen, 0&, 0&
      For i = 0 To lLen - 1
        If b(i) >= 33 Then
          Do
            i = i + 1
          Loop Until b(i) < 33
          WordCount05 = WordCount05 + 1
        End If
      Next
    End If
  End If
End Function
WordCount06
Public Static Function WordCount06(ByRef sText As String) As Long
' by Jost Schwider, jost@schwider.de, http://vb-tec.de/, 20011118
  Dim Chars() As Integer
  Dim SavePtr As Long    'Original Daten-Pointer
  Dim SADescrPtr As Long 'Safe Array Descriptor
  Dim DataPtr As Long    'pvData - Daten-Pointer
  Dim CountPtr As Long   'Pointer zu nElements
  Dim i As Long
  
  'Ggf. Integer-Array einrichten:
  If SavePtr = 0 Then
    ReDim Chars(1 To 1)
    SavePtr = VarPtr(Chars(1))
    PokeLng VarPtr(SADescrPtr), ByVal ArrPtr(Chars)
    DataPtr = SADescrPtr + 12
    CountPtr = SADescrPtr + 16
  End If
  
  'String durch Integer-Array mappen:
  PokeLng DataPtr, StrPtr(sText)
  PokeLng CountPtr, &H7FFFFFFF
  
  'Wörter zählen:
  For i = 1 To Len(sText)
    If Chars(i) > 32 Then
      WordCount06 = WordCount06 + 1
      Do
        i = i + 1
      Loop Until Chars(i) < 33
    End If
  Next i
  
  'Integer-Array restaurieren:
  PokeLng DataPtr, SavePtr
  PokeLng CountPtr, 1&
End Function
WordCount07
Public Static Function WordCount07(ByRef sText As String) As Long
' by Jost Schwider, jost@schwider.de, http://vb-tec.de/, 20011118
  Dim Chars() As Integer 'ASCII-Codes der Zeichen
  Dim Pointer As Long    'Safe Array Descriptor und co.
  Dim i As Long
  
  'Ggf. Integer-Array einrichten:
  If Pointer = 0 Then
    ReDim Chars(1 To 1)
    PokeLng VarPtr(Pointer), ByVal ArrPtr(Chars)
    PokeLng Pointer + 16, &H7FFFFFFF
    Pointer = Pointer + 12
  End If
  
  'String durch Integer-Array mappen:
  PokeLng Pointer, StrPtr(sText)
  
  'Wörter zählen:
  For i = 1 To Len(sText)
    If Chars(i) > 32 Then
      WordCount07 = WordCount07 + 1
      Do
        i = i + 1
      Loop Until Chars(i) < 33
    End If
  Next i
End Function
WordCount08
needs modSafeArray

Public Function WordCount08(ByRef sText As String) As Long ' by Paul - wpsjr1@syix.com, 20011119 Dim lLen As Long Dim lCounter As Long Static saIn As SAFEARRAYHEADER Static lArrayPointer As Long Static iChar() As Integer lLen = Len(sText) If lArrayPointer = 0 Then ReDim iChar(0) lArrayPointer = ArrPtr(iChar) With saIn .DataSize = 2 .dimensions = 1 .sab(0).cElements = &H7FFFFFFF End With RtlMoveMemory ByVal lArrayPointer, VarPtr(saIn), 4 RtlMoveMemory lArrayPointer, ByVal lArrayPointer, 4 End If ' refresh the pointer to the string data RtlMoveMemory ByVal lArrayPointer + 12, StrPtr(sText), 4 If lLen Then lLen = lLen - 1 Do If iChar(lCounter) > 32 Then WordCount08 = WordCount08 + 1 Do lCounter = lCounter + 1 Loop Until iChar(lCounter) < 33 End If lCounter = lCounter + 1 Loop While lCounter <= lLen End If End Function
WordCount09
Public Function WordCount09(ByRef sText As String) As Long
' by Jost Schwider, jost@schwider.de, http://vb-tec.de/, 20011120
  Static Chars() As Integer 'Ascii-Codes der Zeichen
  Static Pointer As Long    'Safe Array Descriptor und co.
  Dim i As Long
  
  'Ggf. Integer-Array einrichten:
  If Pointer = 0& Then
    ReDim Chars(1& To 1&)
    PokeLng VarPtr(Pointer), ByVal ArrPtr(Chars)
    PokeLng Pointer + 16&, &H7FFFFFFF
    Pointer = Pointer + 12&
  End If
  
  'String durch Integer-Array mappen:
  PokeLng Pointer, StrPtr(sText)
  
  'Wörter zählen:
  For i = 1& To Len(sText)
    If Chars(i) > 32 Then
      WordCount09 = WordCount09 + 1&
      Do
        i = i + 1&
      Loop Until Chars(i) < 33
    End If
  Next i
End Function
WordCount10
Public Function WordCount10(ByRef sText As String) As Long
' by Jost Schwider, jost@schwider.de, http://vb-tec.de/, 20011122
  Static Chars() As Integer 'Ascii-Codes der Zeichen
  Static Pointer As Long    'Safe Array Descriptor und co.
  Static SavePtr As Long    'Original Array Data Pointer
  Dim i As Long
  
  'Ggf. Integer-Array einrichten:
  If Pointer = 0& Then
    ReDim Chars(1& To 1&)
    SavePtr = VarPtr(Chars(1))
    PokeLng VarPtr(Pointer), ByVal ArrPtr(Chars)
    PokeLng Pointer + 16&, &H7FFFFFFF
    Pointer = Pointer + 12&
  End If
  
  'String durch Integer-Array mappen:
  PokeLng Pointer, StrPtr(sText)
  
  'Wörter zählen:
  For i = 1& To Len(sText)
    If Chars(i) > 32 Then
      WordCount10 = WordCount10 + 1&
      Do
        i = i + 1&
      Loop Until Chars(i) < 33
    End If
  Next i
  
  'Integer-Array restaurieren, sonst ggf. GPF:
  PokeLng Pointer, SavePtr
End Function
WordCount11
It's a class:

' by Olaf Schmidt, os@datenhaus.de, 20011128 Option Explicit Private Declare Function ArrPtr& Lib "msvbvm60.dll" Alias "VarPtr" (ptr() As Any) Private Declare Sub RtlMoveMemory Lib "kernel32" (dst As Any, src As Any, ByVal nBytes&) Private Declare Function SysAllocStringByteLen& Lib "oleaut32" (ByVal olestr&, ByVal BLen&) Private saSrcL&(5), SrcL&()
Private Sub Class_Initialize() saSrcL(0) = 1: saSrcL(1) = 4: saSrcL(4) = &H7FFFFFFF RtlMoveMemory ByVal ArrPtr(SrcL), VarPtr(saSrcL(0)), 4 End Sub
Friend Function WordCount(s$) As Long Dim i&, SLen&, ub&: Static C32&, C32L& SLen = Len(s): If SLen = 0 Then Exit Function ub = (SLen - 1) \ 2 saSrcL(3) = StrPtr(s): C32& = &H20: C32L& = &H20FFFF For i = 0 To ub If (SrcL(i) And &HFF&) > C32 Then WordCount = WordCount + 1 If SrcL(i) <= C32L Then GoTo m2 i = i + 1: If (SrcL(i) And &HFF&) <= C32 Then GoTo m1 If SrcL(i) <= C32L Then GoTo m2 i = i + 1: If (SrcL(i) And &HFF&) <= C32 Then GoTo m1 If SrcL(i) <= C32L Then GoTo m2 i = i + 1: If (SrcL(i) And &HFF&) <= C32 Then GoTo m1 If SrcL(i) <= C32L Then GoTo m2 i = i + 1: If (SrcL(i) And &HFF&) <= C32 Then GoTo m1 Do If SrcL(i) <= C32L Then GoTo m2 i = i + 1: If (SrcL(i) And &HFF&) <= C32 Then GoTo m1 Loop End If m1: If SrcL(i) > C32L And i <= ub Then WordCount = WordCount + 1 i = i + 1: If (SrcL(i) And &HFF&) <= C32 Then GoTo m1 If SrcL(i) <= C32L Then GoTo m2 i = i + 1: If (SrcL(i) And &HFF&) <= C32 Then GoTo m1 If SrcL(i) <= C32L Then GoTo m2 i = i + 1: If (SrcL(i) And &HFF&) <= C32 Then GoTo m1 If SrcL(i) <= C32L Then GoTo m2 i = i + 1: If (SrcL(i) And &HFF&) <= C32 Then GoTo m1 If SrcL(i) <= C32L Then GoTo m2 Do i = i + 1: If (SrcL(i) And &HFF&) <= C32 Then GoTo m1 If SrcL(i) <= C32L Then GoTo m2 Loop End If m2: Next i End Function
Private Sub Class_Terminate() RtlMoveMemory ByVal ArrPtr(SrcL), 0&, 4 'important End Sub
Calls
1sText = Replicate(10, "word ")
2sText = Replicate(1000, "word ")
3sText = Replicate(1000, "longlonglongword ")
4sText = Replicate(10000, "w" & vbCrLf)
5sText = Replicate(1000, "The WordCount charts outdate faster than the green party's value system. ") ' (Probably the most realistic call ;))
Charts
 VB5 Charts
CodeAuthorDopingNotes
WordCount01 ChrisAPI 
WordCount02 ChrisAPI 
WordCount03 DonaldAPI 
WordCount04 DonaldAPI 
WordCount05 PaulTLB 
WordCount06 JostAPI 
WordCount07 JostAPI 
WordCount08 PaulAPI 
WordCount09 JostAPI 
WordCount10 JostAPI 
WordCount11 OlafAPI 
Call 1
1011.957.597µs
1112.507.947µs
811.537.331µs
911.807.499µs
77.024.466µs
63.992.534µs
32.121.345µs
21.701.082µs
52.541.614µs
42.331.483µs
11.000.636µs
Call 2
113.87188µs
103.27159µs
82.95143µs
92.96144µs
72.95143µs
51.9092µs
41.7786µs
21.1355µs
62.21107µs
31.2058µs
11.0048µs
Call 3
103.05571µs
113.05572µs
83.01563µs
93.01564µs
73.00563µs
52.06386µs
42.02378µs
31.32248µs
62.49467µs
21.27238µs
11.00187µs
Call 4
92.551,114µs
102.621,144µs
72.411,054µs
82.461,074µs
112.641,154µs
61.58692µs
51.48646µs
21.07466µs
11.00437µs
41.25546µs
31.08470µs
Call 5
72.953,014µs
92.993,060µs
82.963,028µs
103.053,124µs
115.715,840µs
62.202,248µs
42.032,081µs
31.531,567µs
52.132,176µs
21.491,528µs
11.001,023µs
 VB6 Charts
CodeAuthorDopingNotes
WordCount01 ChrisAPI 
WordCount02 ChrisAPI 
WordCount03 DonaldAPI 
WordCount04 DonaldAPI 
WordCount05 PaulTLB 
WordCount06 JostAPI 
WordCount07 JostAPI 
WordCount08 PaulAPI 
WordCount09 JostAPI 
WordCount10 JostAPI 
WordCount11 OlafAPI 
Call 1
1012.237.809µs
912.187.778µs
811.977.643µs
1112.447.943µs
76.694.269µs
64.142.647µs
42.091.333µs
31.971.257µs
21.921.226µs
52.381.521µs
11.000.639µs
Call 2
113.64176µs
103.63175µs
93.45166µs
83.40164µs
73.32160µs
61.9293µs
51.7986µs
31.2158µs
41.2159µs
21.1455µs
11.0048µs
Call 3
113.12581µs
103.11580µs
83.07573µs
93.09575µs
72.95550µs
62.04380µs
52.01375µs
41.44268µs
31.44268µs
21.28238µs
11.00187µs
Call 4
102.551,121µs
92.531,113µs
72.351,035µs
82.421,062µs
112.561,124µs
61.60702µs
51.50660µs
11.00440µs
31.01446µs
41.39609µs
21.00441µs
Call 5
93.033,155µs
83.023,145µs
72.993,115µs
103.053,174µs
115.755,991µs
62.132,216µs
52.062,144µs
21.511,570µs
31.511,570µs
41.581,650µs
11.001,042µs
Notes & Conclusions
Don't read this. These comments are outdated faster than the green party's value system.

The only difference between WordCount01 and WordCount02 is the use of a temp var in the latter. The results vary ...
Also note the subtle difference between WordCount03: Const cCharLow As Byte = 33, and WordCount04: Dim cCharLow As Byte: cCharLow = 33. The results vary ...
But who cares after seeing WordCount07. Uh, WordCount08.
Uff, look at WordCount11. Competition is the major doping at work.
Got comments? How to read all those numbers

top




VBspeed © 2000-10 by Donald Lessau