Contents
Articles
Behaviors
Books
Director News
Director Web Sites
FAQ
Games
Mailing Lists
News Groups
Project Examples
Reviews
Software
Tools
Useful Web Sites
Utilities
Xtras

Don't miss these
Basic 4 direction environment navigation
Fake Drag Bar - Stage
Dialing for Behaviors
asFFT 2.0
Can't get picture from field - Valentina
TRAX
Flash Paper in Director Article
Sprite on/off
Open Recordset
VBScript Xtra / ActiveCompanionSet
 

 

 

Article Searching Through Text

Added on 9/27/1999

 

Compatibilities:
D7 D8 Mac PC Shockwave

This item has not yet been rated

Author: MediaMacros (website)

I have a number of text documents that I have imported into text fields and I need to search them in Director. I want the user to enter a keyword and then have Director jump to that article and show the word; plus be able to go foward and back. I have seen Xtras that claim to do this, but can I do it without these?

Get the source
You can put away the credit card for now. Director can search through its own text, but you'll need a little lingo to make it behave the way you want.  Using repeat loops we can sort through text and field members and look for a string.  A first reaction would be to sort through each member and examine every word with the one we are searching, but what happens if we want a phrase, or what if we want to only enter part of a word? Well this looks like a job for the offset command.

Offset will take a text string and return the number of the first character where the string exists in another string.  For example, if we want to find the offset of "Search" in the phrase "Let's search this text", we would use...

offset("search", "Let's search this text")

This would return 7, since the first character of "search" is the 7th character in the longer string.  Now you are probably thinking "Great, problem solved."  Well, not exactly.  Offset will return the 1st occurrence of the word, but we need them all.  So how can we do this?  Lets use a simple repeat loop and a variable to hold our text.  We step through each cast member and place its text in a temporary variable.  Using the offset command we get the first occurrence of the string and add the cast member value, the start character and (using the number of characters in the phrase) the last character.  Then we set a variable for the number of the last character and then delete everything before it.  Now the variable holds everything from the space after the phrase to the end, so using offset will give the next occurrence of the phrase.  We find it and add the value for the number of characters we have deleted.  Here is an example...

We are looking for all occurrences for the word "search" in the phrase "Searching some text? Use this search behavior."  If we use offset and store the values in a list we get a list with the cast member name, the number 1 for the start, and the number 6 for the last char in the string.  Now we set a variable to 6, delete char 1 to 6 and do it again.  This time we get 25.  Add the original 6 to it and we store 31 and 36 for the next occurrence.  Repeat this for the entire string.  Once we are done we have a global list of lists.  Each sub list has all the values we need to show the text.  We can then set the text of our preview member to that of the selected member and then hilite the correct string of characters.

To speed things up we will first run a test on each member.  If it contains the string we continue searching it.  If not, then ignore it and move on.   The example behavior is below.

--Copyright 1999 Chuck Neal
--chuck@mediamacros.com
--If you find this code helpful, send me an e-mail and let me know. :-)

property whichItem, spriteNum, theCastList

global searchResults, itemsList

on getPropertyDescriptionList me
  p_list = [:]
  if the currentSpriteNum > 0 then
    if sprite(the currentSpriteNum).member.type <> #field then
      --is not one of the fields/text members use as one of the buttons
      p_list.addProp(#thecastlist, [#format : #string, #default : "text", #comment : "Which castlib(separate with commas and no spaces):"])
      p_list.addProp(#whichItem, [#format : #symbol, #default : #search, #comment : "Which button:", #range : [#SearchButton, #SearchAgainButton, #searchPreviousButton]])
    else
      p_list.addProp(#whichItem, [#format : #symbol, #default : #SearchField, #comment : "Which field:", #range : [#SearchField, #SearchResults, #Results1, #Results2, #ArticleName]])
    end if
  end if
  return p_list
end

on beginSprite me
  if itemsList = void then itemsList = [#currentSearch : 0]
  --establish where everything is
  itemsList[whichItem] = spriteNum
  --clear the text
  clear()
end

on clear me
  if [#Results1 , #results2, #searchResults, #ArticleName, #searchField].getOne(whichItem) <> 0 then
    sprite(spriteNum).member.text = ""
  end if
end

on mouseDown me
  case whichItem of
    #searchButton :
      itemsList[#currentSearch] = 1
      searchResults = searchText(sprite(itemsList[#searchButton]).theCastList, sprite(itemsList[#searchField]).member.text)
      if searchResults = [] then
        --no results
        alert "No matching results found"
        sendAllSprites(#clear)
      else
        sendAllSprites(#nextSearch)
      end if
    #searchAgainButton :
      if itemsList[#currentSearch] < searchResults.count then
        itemsList[#currentSearch] = itemsList[#currentSearch] + 1
        sendAllSprites(#nextSearch)
      else if searchResults.count > 1 then
        alert "Last found result. Beginning again from first result."
        itemsList[#currentSearch] = 1
        sendAllSprites(#nextSearch)
      else
        alert "There was only one match to your query"
      end if
    #searchPreviousButton :
      if itemsList[#currentSearch] > 1 then
        itemsList[#currentSearch] = itemsList[#currentSearch] - 1
        sendAllSprites(#nextSearch)
      else if searchResults.count > 1 then
        alert "This is the first result. Returning to the end of the list."
        itemsList[#currentSearch] = searchResults.count
        sendAllSprites(#nextSearch)
      else
        alert "There was only one match to your query"
      end if
  end case
end

on nextSearch me
  case whichItem of
    #Results1 :
      sprite(spriteNum).member.text = string(itemsList[#currentSearch])
    #results2 :
      sprite(spriteNum).member.text = string(searchResults.count)
    #searchResults :
      --see if it is the same member as the last search
      if sprite(spriteNum).member.text <> searchResults[itemsList[#currentSearch]][1].text then
        sprite(spriteNum).member.text = searchResults[itemsList[#currentSearch]][1].text
      end if
      sprite(spriteNum).member.scrolltop = (charPosToLoc(sprite(spriteNum).member, searchResults[itemsList[#currentSearch]][2])).locV - (sprite(spriteNum).member.lineheight)
      hilite char searchResults[itemsList[#currentSearch]][2] to searchResults[itemsList[#currentSearch]][3] of member the member of sprite spriteNum
    #ArticleName :
      sprite(spriteNum).member.text = searchResults[itemsList[#currentSearch]][1].name
  end case
end

on searchText castlist, textString
  resultList = []
  the itemDelimiter = ","
  repeat with x = 1 to castlist.item.count
    repeat with y = 1 to (the number of members of castlib x)
      if [#text, #field].getOne(member(y, castlist.item[x]).type) <> 0 then
        if member(y, castlist.item[x]).text contains textString then
          --string is in the text search for all instances
          offsetItem = 0
          tempText = member(y, castlist.item[x]).text
          repeat while tempText contains textString
            theOffset = offset(textString, tempText)
            offSetEnd = theOffset + (textString.char.count - 1)
            resultList.add([member(y, castlist.item[x]), theOffset + offsetItem, offsetEnd + offsetItem])
            offsetItem = offsetItem + offsetEnd
            tempText = tempText.char[(offsetEnd + 1)..(tempText.char.count)]
          end repeat
        end if
      end if
    end repeat
  end repeat
  return resultList
end

on getBehaviorDescription me
  describe = "This behavior sets up a text search. Use field members for the search field, result box, name of the article, current result number, and total results."
  describe = describe & return & "For the buttons use any other type of cast member. On the searchButton declare the list of the cast libraries to search as a text string separated by commas and no extra spaces."
  return describe
end

In the beginSprite handler, each item adds itself to a global list so that every other piece knows where it is in the score.  This way you can use the global itemList to get the sprite number of any piece fo the "system".

Give it a try with the good old readme from Director 7.02 and download the source file here.  Try some keywords like "support", "Macintosh", "PC", etc.

Want some more ideas?  How about modifying this to search pre-built lists for external files, or maybe lists of keywords for images.  Play with it and see what you come up with.

 


Contact

MMI
36 South Court Sq
Suite 300
Newnan, GA 30263
USA

Send e-mail