home *** CD-ROM | disk | FTP | other *** search
/ Planet Source Code Jumbo …e CD Visual Basic 1 to 7 / 6_2008-2009.ISO / data / zips / Fast_Sub-S2169531272009.psc / SubStrCount / SubStrCnt.bas < prev    next >
BASIC Source File  |  2009-11-28  |  10KB  |  258 lines

  1. Attribute VB_Name = "mSubStrCnt"
  2. Option Explicit
  3.  
  4. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''⌐Rd'
  5. '
  6. '                        Sub-String Count
  7. '
  8. '  This function searches the passed string for occurences of the
  9. '  specified sub-string. It has the ability to make case-sensitive
  10. '  or case-insensitive searches.
  11. '
  12. '  It can also perform whole-word-only matching using a unique
  13. '  delimiter function included in this module.
  14. '
  15. '  SubStrCount will return the number of matches or zero if none.
  16. '
  17. '                     Extended Functionality
  18. '
  19. '  This SubStrCount implementation offers extended functionality
  20. '  through the use of the optional lHitLimit parameter. This allows
  21. '  it to be used in a similar way to other token style functions.
  22. '
  23. '  By passing the lHitLimit parameter as any positive value allows
  24. '  you to limit how many matches are found in the current call, and
  25. '  the value of the lStartPos parameter *is modified* to identify the
  26. '  start position in the search string of the last sub-string found
  27. '  (or zero if none found).
  28. '
  29. '  In this case, the function will return a value equal to or less
  30. '  than the value of the lHitLimit parameter, and zero if none found.
  31. '
  32. '  Using this feature you can limit the number of matches found, and
  33. '  make subsequent calls to SubStrCount by passing lStartPos + 1
  34. '  (or lStartPos + Len(sSubStr)) to step through the search process
  35. '  as needed, and stop when the function returns zero.
  36. '
  37. '                        Whole-Word-Only
  38. '
  39. '  By default, all non-alphabetic characters (with the exception of
  40. '  underscores) are automatically treated as word delimiters when
  41. '  performing whole-word-only seaches and do not need to be specified.
  42. '
  43. '  As only alphabetic characters are treated as non-delimiters you
  44. '  can specify custom non-delimiters, that is, any character(s) can
  45. '  be specified as part of whole words and therefore be treated as
  46. '  non-delimiters.
  47. '
  48. '  To make numerical characters part of whole words and so set
  49. '  as non-delimiters *by default* add this line to the IsDelim
  50. '  function's select case statement:
  51. '      Case 48 To 57: IsDelim = False
  52. '
  53. '  To specify custom/run-time changes to the list of delimiters make
  54. '  a call to the public SetDelim subroutine and add character(s) to
  55. '  be handled as part of whole words (or as delimiters):
  56. '      SetDelim "1234567890", False
  57. '
  58. '  Remember, all non-alphabetic characters are already treated as
  59. '  word delimiters and so do not need to be specified through a
  60. '  call to SetDelim ???, True. Also, alphabetic characters can be
  61. '  treated as word delimiters through a call to SetDelim "a", True.
  62. '
  63. '  Most delimiter implementations build a list/array to hold all
  64. '  delimiters, but this modules approach is *much* faster.
  65. '
  66. '                            Notes
  67. '
  68. '  Passing lStartPos with a value < 1 will not cause an error; it
  69. '  will default to 1 and start the search at the first character in
  70. '  the search string.
  71. '
  72. '  The lStartPos parameter will be reset appropriately if lHitLimit
  73. '  is specified > zero, but will be *left unchanged* if lHitLimit
  74. '  is omitted or passed with a value <= zero.
  75. '
  76. '                          Free Usage
  77. '
  78. '  You may use this code in any way you wish, but please respect
  79. '  my copyright. But, if you can modify this function in some way
  80. '  to speed it up or to add extra features then you can claim it
  81. '  as your own!
  82. '
  83. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  84.  
  85. Private mDelimList As String
  86. Private mNotDelim As String
  87.  
  88. 'Sub-String Count''''''''''''''''''''''''''''''''''''''''''''''''
  89. '  Function to search for occurences of a sub-string.
  90. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  91. Public Function SubStrCount(sStr As String, _
  92.                             sSubStr As String, _
  93.                             Optional lStartPos As Long = 1, _
  94.                             Optional ByVal lCompare As _
  95.                             VbCompareMethod = vbBinaryCompare, _
  96.                             Optional ByVal bWordOnly As Boolean, _
  97.                             Optional ByVal lHitLimit As Long _
  98.                             ) As Long ' ⌐Rd
  99.  
  100.     Dim sStrV As String, sSubStrV As String
  101.     Dim lLenStr As Long, lLenSub As Long
  102.     Dim lBefore As Long, lAfter As Long
  103.     Dim lStartV As Long, lHit As Long
  104.     Dim lOffStart As Long, bDelim As Boolean
  105.  
  106.     On Error GoTo FreakOut
  107.  
  108.     lLenStr = Len(sStr)
  109.     If (lLenStr = 0) Then Exit Function ' No text
  110.  
  111.     lLenSub = Len(sSubStr)
  112.     If (lLenSub = 0) Then Exit Function ' Nothing to find
  113.  
  114.     If (lStartPos < 1) Then lHit = 1 Else lHit = lStartPos
  115.  
  116.     If (lCompare = vbTextCompare) Then
  117.         ' Better to convert once to lowercase than on every call to InStr
  118.         sSubStrV = LCase$(sSubStr): sStrV = LCase$(sStr)
  119.  
  120.         lHit = InStr(lHit, sStrV, sSubStrV, vbBinaryCompare)
  121.     Else                         ' Do first search
  122.         lHit = InStr(lHit, sStr, sSubStr, vbBinaryCompare)
  123.     End If
  124.  
  125.     Do While (lHit)    ' Do until no more hits
  126.  
  127.         If bWordOnly = False Then
  128.  
  129.             lStartV = lHit
  130.             SubStrCount = SubStrCount + 1
  131.             If (SubStrCount = lHitLimit) Then Exit Do
  132.  
  133.             lOffStart = lLenSub ' Offset next start pos
  134.         Else
  135.             lOffStart = 1 ' Default offset start pos
  136.  
  137.             lBefore = lHit - 1
  138.             If (lBefore = 0) Then
  139.                 bDelim = True
  140.             Else
  141.                 bDelim = IsDelim(Mid$(sStr, lBefore, 1))
  142.             End If
  143.  
  144.             If bDelim Then
  145.  
  146.                 lAfter = lHit + lLenSub
  147.                 If (lAfter > lLenStr) Then
  148.                     bDelim = True
  149.                 Else
  150.                     bDelim = IsDelim(Mid$(sStr, lAfter, 1))
  151.                 End If
  152.  
  153.                 If bDelim Then
  154.  
  155.                     lStartV = lHit
  156.                     SubStrCount = SubStrCount + 1
  157.                     If (SubStrCount = lHitLimit) Then Exit Do
  158.  
  159.                     lOffStart = lLenSub ' Offset next start pos
  160.                 End If
  161.             End If
  162.         End If
  163.  
  164.         If (lCompare = vbTextCompare) Then
  165.             lHit = InStr(lHit + lOffStart, sStrV, sSubStrV)
  166.         Else
  167.             lHit = InStr(lHit + lOffStart, sStr, sSubStr)
  168.         End If
  169.     Loop
  170.  
  171.     If (lHitLimit > 0) Then lStartPos = lStartV
  172. FreakOut:
  173. End Function
  174.  
  175. 'IsDelim'''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  176. '  This function is called by the SubStrCount function during a
  177. '  whole word only procedure. You can also call this function
  178. '  from your own code - very handy for string parsing.
  179. '
  180. '  It checks if the character passed is a common word delimiter,
  181. '  and then returns True or False accordingly.
  182. '
  183. '  By default, any non-alphabetic character is considered a word
  184. '  delimiter, including underscores, apostrophes and numbers.
  185. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  186. Public Function IsDelim(Char As String) As Boolean ' ⌐Rd
  187.     Select Case Asc(Char)
  188.         ' Uppercase, Underscore, Lowercase chars not delimiters
  189.         Case 65 To 90, 95, 97 To 122: IsDelimI = False
  190.  
  191.         'Case 39, 146: IsDelim = False  ' Apostrophes not delimiters
  192.         'Case 48 To 57: IsDelim = False ' Numeric chars not delimiters
  193.  
  194.         Case Else: IsDelim = True ' Any other character is delimiter
  195.     End Select
  196.     If (IsDelim) And Not (LenB(mNotDelim) = 0) Then
  197.         If Not (InStr(mNotDelim, Char) = 0) Then
  198.             IsDelim = False
  199.             ' SetDelim doesn't allow chars to repeat
  200.             ' in both lists so we can exit
  201.             Exit Function
  202.         End If
  203.     End If
  204.     If Not (IsDelim) And Not (LenB(mDelimList) = 0) Then
  205.         ' May need alphabetic characters to behave as delimiters
  206.         IsDelim = Not (InStr(mDelimList, Char) = 0)
  207.     End If
  208. End Function
  209.  
  210. 'SetDelim''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  211. '  Specifies whether character(s) should be handled as delimiter
  212. '  in whole word only searches.
  213. '
  214. '  Note that all non-alphabetic characters are already treated
  215. '  as word delimiters by default and do not need to be specified
  216. '  through SetDelim.
  217. '
  218. '  Note that multiple characters must not be seperated by spaces
  219. '  or any other character.
  220. '
  221. '  For example, to set all numeric charaters, underscores and
  222. '  apostrophes as part of whole words (non-delimiters):
  223. '
  224. '  SetDelim "1234567890_'Æ", False
  225. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  226. Public Sub SetDelim(Char As String, Optional IsDelimiter As Boolean) ' ⌐Rd
  227.     On Error GoTo ErrHandler
  228.     Dim iPos As Long, sChr As String
  229.     Dim fIs As Boolean, fNot As Boolean
  230.     Dim idx1 As Long, idx2 As Long
  231.  
  232.     fIs = Not (LenB(mDelimList) = 0)
  233.     fNot = Not (LenB(mNotDelim) = 0)
  234.  
  235.     For iPos = 1 To Len(Char)
  236.         sChr = Mid$(Char, iPos, 1)
  237.         If fIs Then idx1 = InStr(mDelimList, sChr)
  238.         If fNot Then idx2 = InStr(mNotDelim, sChr)
  239.  
  240.         If IsDelimiter Then
  241.             If (idx1 = 0) Then mDelimList = mDelimList & sChr
  242.             If Not (idx2 = 0) Then
  243.                 mNotDelim = Left$(mNotDelim, idx2 - 1) & Mid$(mNotDelim, idx2 + 1)
  244.             End If
  245.         Else
  246.             If (idx2 = 0) Then mNotDelim = mNotDelim & sChr
  247.             If Not (idx1 = 0) Then
  248.                 mDelimList = Left$(mDelimList, idx1 - 1) & Mid$(mDelimList, idx1 + 1)
  249.             End If
  250.         End If
  251.     Next iPos
  252. ErrHandler:
  253. End Sub
  254.  
  255. ' Rd - crYptic but cRaZy!                                      :)
  256. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  257. '
  258.