• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 307
  • Last Modified:

Searching an array for strings

I created an array to hold and entire Ebook name  "Ebook()". The array holds all the versus of the Bible. First, should the array be String or Byte? Also, could someone provide Search engine code to search for words or phrases in the Ebook() array.  Thanks!
0
mcdonald_g
Asked:
mcdonald_g
  • 10
  • 4
  • 3
  • +1
2 Solutions
 
David LeeCommented:
The array should be of string or variant.  Here's a function to search the array.

Option Base 1     'Because I hate 0 based arrays
Private Function SearchArray(strSearchText As String) As Integer
    Dim intItem As Integer
    For intItem = 1 To UBound(Ebook)
        If InStr(1, Ebook(intItem), strSearchText, vbTextCompare) > 0 Then
            SearchArray = intItem
            Exit For
        End If
    Next
End Function

To use this function include something like:

     x = SearchArray("some word or phrase")

The function's search is case sensitive and will stop searching on the first match.

0
 
David LeeCommented:
Oh, and I should have mentioned that if the search finds nothing it returns a 0.  Otherwise it'll return the elment number of the item containing the search string/phrase.
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
If we modify BlueDevilFans function a little, then we can continue our search from the last match found.  Here is an example of how to use it.  Create a new project and add a TextBox, CommandButton and a Label:

Option Explicit
Option Base 1     'Because I hate 0 based arrays
   
Private verseIndex As Long
Private Ebook As Variant

Private Sub Form_Load()
    ReDim Ebook(5)
    Ebook(1) = "Genesis 1:1 In the beginning God created the heaven and the earth."
    Ebook(2) = "Genesis 1:2 Now the earth was unformed and void, and darkness was upon the face of the deep; and the spirit of God hovered over the face of the waters."
    Ebook(3) = "Genesis 1:3 And God said: 'Let there be light.' And there was light."
    Ebook(4) = "Genesis 1:4 And God saw the light, that it was good; and God divided the light from the darkness."
    Ebook(5) = "Genesis 1:5 And God called the light Day, and the darkness He called Night. And there was evening and there was morning, one day."
   
    Text1.Text = "light"
    Label1.Caption = ""
    Command1.Caption = "Search"
End Sub
   
Private Sub Text1_Change()
    verseIndex = 0
    Command1.Caption = "Search"
End Sub
       
Private Sub Command1_Click()
    If Text1.Text <> "" Then
        verseIndex = SearchArray(Text1.Text, verseIndex)
        If verseIndex <> 0 Then
            Label1.Caption = Ebook(verseIndex)
            If verseIndex <> UBound(Ebook) Then
                Command1.Caption = "Find Next"
            Else
                verseIndex = 0
                MsgBox "Last Verse Reached", vbInformation, "Search"
                Command1.Caption = "Search Again"
            End If
        Else
            Label1.Caption = "No Match Found"
            Command1.Caption = "Search"
        End If
    End If
End Sub

Private Function SearchArray(ByVal strSearchText As String, ByVal lastIndex As Long) As Long
    Dim intItem As Long
    For intItem = (lastIndex + 1) To UBound(Ebook)
        If InStr(1, Ebook(intItem), strSearchText, vbTextCompare) > 0 Then
            SearchArray = intItem
            Exit For
        End If
    Next
End Function
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
Mike TomlinsonMiddle School Assistant TeacherCommented:
If you change SearchArray to the below, then it will a find verses that contains any of the words (seperated by spaces) in the textbox:

Private Function SearchArray(ByVal strSearchText As String, ByVal lastIndex As Long) As Long
    Dim intItem As Long
    Dim intWord As Byte
    Dim words As Variant
    Dim curVerse As String
   
    words = Split(strSearchText, " ")
    For intItem = (lastIndex + 1) To UBound(Ebook)
        curVerse = Ebook(intItem)
        For intWord = LBound(words) To UBound(words)
            If InStr(1, curVerse, words(intWord), vbTextCompare) > 0 Then
                SearchArray = intItem
                Exit Function
            End If
        Next
    Next
    If lastIndex > 1 Then
        SearchArray = -1
    End If
End Function
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
I also changed Command1_Click() to handle the new return value of -1 from SearchArray().

Sorry, here is the whole thing with the changes that allow finds matches if any of the words in the textbox are found in the verse:

Option Explicit
Option Base 1     'Because I hate 0 based arrays
   
Private verseIndex As Long
Private Ebook As Variant

Private Sub Form_Load()
    ReDim Ebook(5)
    Ebook(1) = "Genesis 1:1 In the beginning God created the heaven and the earth."
    Ebook(2) = "Genesis 1:2 Now the earth was unformed and void, and darkness was upon the face of the deep; and the spirit of God hovered over the face of the waters."
    Ebook(3) = "Genesis 1:3 And God said: 'Let there be light.' And there was light."
    Ebook(4) = "Genesis 1:4 And God saw the light, that it was good; and God divided the light from the darkness."
    Ebook(5) = "Genesis 1:5 And God called the light Day, and the darkness He called Night. And there was evening and there was morning, one day."
   
    verseIndex = 0
    Text1.Text = "light"
    Label1.Caption = ""
    Command1.Caption = "Search"
End Sub
   
Private Sub Text1_Change()
    verseIndex = 0
    Command1.Caption = "Search"
End Sub
       
Private Sub Command1_Click()
    If Text1.Text <> "" Then
        verseIndex = SearchArray(Text1.Text, verseIndex)
        Select Case verseIndex
            Case 0
                Label1.Caption = "[No Match Found]"
                Command1.Caption = "Search"
                MsgBox "No Match Found", vbInformation, "Search"
               
            Case Is > 0
                Label1.Caption = Ebook(verseIndex)
                Command1.Caption = "Find Next"
               
            Case -1
                verseIndex = 0
                Command1.Caption = "Search Again"
                MsgBox "Last Verse Reached", vbInformation, "Search"
               
        End Select
    End If
End Sub

Private Function SearchArray(ByVal strSearchText As String, ByVal lastIndex As Long) As Long
    Dim intItem As Long
    Dim intWord As Byte
    Dim words As Variant
    Dim curVerse As String
   
    words = Split(strSearchText, " ")
    For intItem = (lastIndex + 1) To UBound(Ebook)
        curVerse = Ebook(intItem)
        For intWord = LBound(words) To UBound(words)
            If InStr(1, curVerse, words(intWord), vbTextCompare) > 0 Then
                SearchArray = intItem
                Exit Function
            End If
        Next
    Next
    If lastIndex > 1 Then
        SearchArray = -1
    End If
End Function
0
 
mcdonald_gAuthor Commented:
Thanks Idle Mind
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Thank you for giving BlueDevilFan assist points.

I have been getting so much flack lately when I modify someone elses submission and then get all the points.

~IM
0
 
David LeeCommented:
Thanks for the consideration, Idle_Mind.  I appreciate it!  Nice bit of coding too.  It makes the routine much more functional.
0
 
mcdonald_gAuthor Commented:
BlueDevilFan, I thank you also.
0
 
mcdonald_gAuthor Commented:
Guys, I hope you will be available for help with this function in the future
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Feel free to post here if you need additional help with it.

~IM
0
 
amebaCommented:
Use Filter() function - it returns array of matches:

        Dim matches() As String, nummatches As Long, i As Long
        matches = Filter(Ebook, Text1.Text, True, vbTextCompare)
        nummatches = UBound(matches) + 1
        Caption = nummatches & " matches found"
        For i = 0 To nummatches - 1
            Debug.Print matches(i)
        Next
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Your code is definitely more compact ameba!

The only drawback I see is that if you have someting huge, like the entire bible as in this case, then your matches could take up a lot of memory (possible doubling the amount of memory used if you searched for something silly like "a").  With the other approach presented here you don't use any additional memory and you can still find the next match.

~IM
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Also the filter function can only search for one value (or more than one value but they all have to be together in an exact match like a phrase).

You can do multiple Filter calls but then you may have duplicate results.

~IM
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
mcdonald_g,

One last version of my "search engine".  Create a new project and add a TextBox, CommandButton, CheckBox and a Label.  If the CheckBox is checked then the verse must have all of the words in the search criteria to be a match.  If the CheckBox is unchecked then the verse only needs one of the words in the search criteria to be a match.

~IM

Option Explicit
Option Base 1     'Because I hate 0 based arrays
   
Private verseIndex As Long
Private Ebook As Variant

Private Sub Form_Load()
    ReDim Ebook(5)
    Ebook(1) = "Genesis 1:1 In the beginning God created the heaven and the earth."
    Ebook(2) = "Genesis 1:2 Now the earth was unformed and void, and darkness was upon the face of the deep; and the spirit of God hovered over the face of the waters."
    Ebook(3) = "Genesis 1:3 And God said: 'Let there be light.' And there was light."
    Ebook(4) = "Genesis 1:4 And God saw the light, that it was good; and God divided the light from the darkness."
    Ebook(5) = "Genesis 1:5 And God called the light Day, and the darkness He called Night. And there was evening and there was morning, one day."
   
    verseIndex = 0
    Text1.Text = "light"
    Label1.Caption = ""
    Command1.Caption = "Search"
    Check1.Caption = "Must contain all values"
End Sub
   
Private Sub Text1_Change()
    verseIndex = 0
    Command1.Caption = "Search"
End Sub

Private Sub Check1_Click()
    verseIndex = 0
    Command1.Caption = "Search"
End Sub
   
Private Sub Command1_Click()
    If Text1.Text <> "" Then
        verseIndex = SearchArray(Text1.Text, verseIndex)
        Select Case verseIndex
            Case 0
                Label1.Caption = "[No Match Found]"
                Command1.Caption = "Search"
                MsgBox "No Match Found", vbInformation, "Search"
               
            Case Is > 0
                Label1.Caption = Ebook(verseIndex)
                Command1.Caption = "Find Next"
               
            Case -1
                verseIndex = 0
                Command1.Caption = "Search Again"
                MsgBox "Last Verse Reached", vbInformation, "Search"
               
        End Select
    End If
End Sub

Private Function SearchArray(ByVal strSearchText As String, ByVal lastIndex As Long) As Long
    Dim intItem As Long
    Dim intWord As Byte
    Dim words As Variant
    Dim curVerse As String
    Dim allWords As Boolean
   
    words = Split(strSearchText, " ")
    For intItem = (lastIndex + 1) To UBound(Ebook)
        curVerse = Ebook(intItem)
        allWords = True
        For intWord = LBound(words) To UBound(words)
            If InStr(1, curVerse, words(intWord), vbTextCompare) > 0 Then
                If Check1.Value = vbUnchecked Then
                    SearchArray = intItem
                    Exit Function
                End If
            Else
                allWords = False
                If Check1.Value = vbChecked Then
                    Exit For
                End If
            End If
        Next
        If Check1.Value = vbChecked And allWords = True Then
            SearchArray = intItem
            Exit Function
        End If
    Next
    If lastIndex > 0 Then
        SearchArray = -1
    End If
End Function
0
 
amebaCommented:
Hi IM,
It still doesn't return number of matches... hehe :)

For multiple words, Filter can be executed for the first word, then result array is filtered for the second, it isn't bad at all, it is one of efficient string functions introduced in VB6 (like Replace, Join...).
And it is easy to implement "does not contain" syntax: "light -darkness".

VB's Instr is not very efficient, to find only if there is a match, without knowing position, Like operator is faster.
0
 
amebaCommented:
mcdonald_g,
Is there a download of complete text you are using?
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
True, my algorithm won't give you the number of matches.

I need to use "Like" more often.  I alway forget it's there.

For finding strings that contain all of the words, I can see how using the Filter in a loop would be nice.

For finding strings that contain any of the words, I suppose your could use a collection and place the resultings strings in it using the string as the key and value to remove duplicates.

The whole memory usage thing still bothers me a little though.  =)

~IM
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
I like both approaches as they each have their own benefits and depending on the application, one approach may be better suited than the other.

My approach only returns the next match found but doesn't keep additional copies of the verses in memory.  The code is longer and more complicated.

Using amebas suggested filter approach, you will know how many matches there are and can display all of them at once, but all of the matches found will be copied to a seperate array using more memory (this isn't necessarily a problem, just a drawback in my opinion).  Implementing a search to include all words will look elegant in a For...Next loop that applies the filter repeatedly for each word in the criteria.  Implementing a search to include any of the words will be a little messier though if you want to remove duplicate strings found.

In this case, it would probably make sense to be able to view all of the matches at once.  Given the size of the dataset and the possibility of a large number of matches though, memory consumption is still a concern for me.  Under perfect conditions, I would store the verses in a database and use queries to find matches.  The search may take a little longer but it I think memory would be better utilized.

~IM
0
 
mcdonald_gAuthor Commented:
Guys I know this question was posted months ago, however I'm still working on the project in which comments are posted.  I have the Bible stored in an Access database utilizing structured tables and fields. I need a super-fast way to search the database or memory (if the database is stored in an array). All positive return matched should be posted in an listbox.  I can post more points again if requested.  I hope you responed to this request.  I can email a copy of the DB if needed.
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 10
  • 4
  • 3
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now