Solved

Searching an array for strings

Posted on 2004-09-24
20
296 Views
Last Modified: 2010-05-02
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
Comment
Question by:mcdonald_g
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 10
  • 4
  • 3
  • +1
20 Comments
 
LVL 76

Assisted Solution

by:David Lee
David Lee earned 125 total points
ID: 12148029
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
 
LVL 76

Expert Comment

by:David Lee
ID: 12148035
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
 
LVL 86

Accepted Solution

by:
Mike Tomlinson earned 125 total points
ID: 12148189
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
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!

 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 12148279
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
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 12148289
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
 

Author Comment

by:mcdonald_g
ID: 12148308
Thanks Idle Mind
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 12148336
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
 
LVL 76

Expert Comment

by:David Lee
ID: 12148573
Thanks for the consideration, Idle_Mind.  I appreciate it!  Nice bit of coding too.  It makes the routine much more functional.
0
 

Author Comment

by:mcdonald_g
ID: 12148999
BlueDevilFan, I thank you also.
0
 

Author Comment

by:mcdonald_g
ID: 12149009
Guys, I hope you will be available for help with this function in the future
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 12149013
Feel free to post here if you need additional help with it.

~IM
0
 
LVL 15

Expert Comment

by:ameba
ID: 12150739
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
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 12150904
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
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 12150923
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
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 12150970
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
 
LVL 15

Expert Comment

by:ameba
ID: 12151124
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
 
LVL 15

Expert Comment

by:ameba
ID: 12151179
mcdonald_g,
Is there a download of complete text you are using?
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 12151200
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
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 12151246
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
 

Author Comment

by:mcdonald_g
ID: 12882456
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

Technology Partners: 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!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction While answering a recent question (http://www.experts-exchange.com/Q_27402310.html) in the VB classic zone, I wrote some VB code in the (Office) VBA environment, rather than fire up my older PC.  I didn't post completely correct code o…
Enums (shorthand for ‘enumerations’) are not often used by programmers but they can be quite valuable when they are.  What are they? An Enum is just a type of variable like a string or an Integer, but in this case one that you create that contains…
Get people started with the process of using Access VBA to control Outlook using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Microsoft Outlook. Using automation, an Access applic…
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…

739 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question