Searching a field
March 16, 1998
by Pat McClellan
Dear Multimedia Handyman,
I'm creating a training program with many text fields. Someone suggested that we created it in Authorware so that we could have text search capabilities. I'm much more comfortable with Director, but I don't know how to search through text. Can you help?
Signed,
Word Smith
Dear Smitty,
Have no fear. Though Authorware excels at text handling, Director and Lingo are extremely capable as well. If the quantity of text is enormous -- say, an Encyclopedia -- I recommend you check out Meetinghouse Tech's MHT-Search. I was very impressed by the speed of this XTRA when I saw it demonstrated at UCON, though it's not cheap. So, you may want to do the search yourself by creating your own handlers to meet your specific needs.
First, I'd recommend a quick review of Chapter 7 of your Learning Lingo manual. It's a great refresher on handling text. Key lingo term to note: contains. You can use this term to determine if a keyword is contained within a particular chunk of text. For example, let's say that your text field is named "example" and includes the text of this paragraph.
put field "example" contains "refresher" -- 1 put field "example" contains "astronaut" -- 0This demonstrates that contains determined that the word "refresher" was included in the last paragraph, while "astronaut" was not.
For this article, I'll limit our search to a single text field, though it would be easy to set up a list of all text fields to be searched, then cycle through them. Also, for simplicity, I'll simply be counting the number of instances that the search word appears in a sample text field that is in the movie's cast. In your case, you may want to have the handler return the location of the word or display the text and scroll to the appropriate line.
Let's start with the slow way to do it. This approach would be to proceed through each word in your text field to see if it equals the search word. I have set this up in the demo movie below. Some good words to search for: computer, screen, control, director. (NOTE: In this demo movie, I'm repeating the search 10 times in each case, in order to get a better comparison of relative search times. The actual times would be 10X faster. My sample text is 332 lines and 1882 words.)
on testEachWord keyWord set startTicks = the ticks set wordCount = 0 set theText = the text of field "sample text" set numOfWords = the number of words in theText repeat with i = 1 to numOfWords if word i of theText = keyWord then set wordCount = wordCount + 1 end if end repeat put wordCount into field "display" endThe only thing I did in this handler that optimizes speed is that I put the text of field "sample text" into a variable before doing the search. I don't know why, but searching the text in a variable is faster that simply searching the text field. In my tests, approximately 6% faster. So what did I do wrong?
Let's say that you want to find a word in a dictionary. Do you start looking on the first page? Nope. Waste of time. First you see which letter the word starts with and turn immediately to that section. Then, you check the indexes to help you skip to the right page. Only then do you begin your word by word search. Now let's apply that concept to our Search Engine. Instead of word-by-word, let's search line-by-line. If a line contains the key word, then we'll search that line word-by-word; if not, we'll save time and move on to the next line.
on testLine keyWord set wordCount = 0 set theText = the text of field "sample text" set numOfLines = the number of lines in theText repeat with whichLine = 1 to numOfLines set theLine = line whichLine of theText if theLine contains keyWord then set numOfWords = the number of words in theLine repeat with thisWord = 1 to numOfWords if word thisWord of theLine = keyWord then set wordCount = wordCount + 1 end if end repeat end if end repeat put wordCount into field "display" endThis approach results in a huge time savings. Test it on the word "computer", first "Word by Word", then "Line, then Word". In my tests, checking the line first cuts the time to about 20% of the Word by Word approach. When I discovered this, I was excited to see just how far I could push it.
Here's my final approach: First, check to see if the field contains the word. If so, then divide the field into 8 sectors and then check the sectors one by one to see if the sector contains the key word. (8 sectors is arbitrary, though with my sample text, it was faster than 5 sectors and faster than 12 sectors. To facilitate experimentation, I use a global variable to set the number of sectors. This variable is set in the start movie script.) If the sector contains the key word, then we'll do the line search, and finally the word search. Test it out on the word "computer" and compare it to the previous search times. Remember that the time displayed is 10 times the actual speed. Also, try a test word the won't be in the text (use "astronaut"). This final approach is almost instantaneous.
on testField keyword global wordCount set wordCount = 0 set theText = the text of field "sample text" if theText contains keyword then testSectors theText, keyword end if end repeat put wordCount into field "display" end
on testSectors theText, keyWord global gSectors set numOfLines = the number of lines in theText set linesPerSector = integer(numOfLines/gSectors) repeat with sectorNum = 0 to (gSectors - 1) set secFirstLine = (sectorNum * linesPerSector) + 1 if sectorNum = 9 then set secLastLine = numOfLines else set secLastLine = (sectorNum * linesPerSector) ¬ + linesPerSector end if set theSector = line secFirstLine to secLastLine ¬ of theText if theSector contains keyWord then testLines theSector, keyWord end if end repeat end
on testLines theSector, keyWord, wordCount set numOfLines = the number of lines in theSector repeat with whichLine = 1 to numOfLines set theLine = line whichLine of theSector if theLine contains keyWord then testWords theLine, keyWord end if end repeat end
on testWords theLine, keyWord global wordCount set numOfWords = the number of words in theLine repeat with whichWord = 1 to numOfWords if word whichWord of theLine = keyWord then set wordCount = wordCount + 1 end if end repeat end
For clarity, I broke this routine into several handlers... one that tests sectors, one for lines, one for words. Good luck with your project and let me know how you adapt this to meet your specific needs.
Copyright 1997-2024, Director Online. Article content copyright by respective authors.