Solved

Searching an array for strings

Posted on 2004-09-24
20
288 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
  • 10
  • 4
  • 3
  • +1
20 Comments
 
LVL 76

Assisted Solution

by:David Lee
David Lee earned 125 total points
Comment Utility
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
Comment Utility
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 85

Accepted Solution

by:
Mike Tomlinson earned 125 total points
Comment Utility
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
 
LVL 85

Expert Comment

by:Mike Tomlinson
Comment Utility
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 85

Expert Comment

by:Mike Tomlinson
Comment Utility
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
Comment Utility
Thanks Idle Mind
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
Comment Utility
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
Comment Utility
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
Comment Utility
BlueDevilFan, I thank you also.
0
 

Author Comment

by:mcdonald_g
Comment Utility
Guys, I hope you will be available for help with this function in the future
0
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 85

Expert Comment

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

~IM
0
 
LVL 15

Expert Comment

by:ameba
Comment Utility
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 85

Expert Comment

by:Mike Tomlinson
Comment Utility
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 85

Expert Comment

by:Mike Tomlinson
Comment Utility
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 85

Expert Comment

by:Mike Tomlinson
Comment Utility
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
Comment Utility
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
Comment Utility
mcdonald_g,
Is there a download of complete text you are using?
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
Comment Utility
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 85

Expert Comment

by:Mike Tomlinson
Comment Utility
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
Comment Utility
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

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

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…
The debugging module of the VB 6 IDE can be accessed by way of the Debug menu item. That menu item can normally be found in the IDE's main menu line as shown in this picture.   There is also a companion Debug Toolbar that looks like the followin…
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 utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…

771 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

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now