Articles Archive
Articles Search
Director Wiki
 

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"
-- 0

This 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.)

You need <a href='http://www.macromedia.com/shockwave/'>ShockWave</a> 6 to view this movie!

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"
end
The 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"  
end
This 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.

Patrick McClellan is Director Online's co-founder. Pat is Vice President, Managing Director for Jack Morton Worldwide, a global experiential marketing company. He is responsible for the San Francisco office, which helps major technology clients to develop marketing communications programs to reach enterprise and consumer audiences.

Copyright 1997-2024, Director Online. Article content copyright by respective authors.