• 1 reply
  • Latest Post - ‏2013-02-01T19:12:51Z by llandale
3180 Posts

Pinned topic Search menu

‏2013-02-01T18:16:47Z |

Trying to make a user menu so users can enter their specifc terms in a dialogue box and have it search through the file.

I am trying a loop that can parse a the string separated by commas into an array or another string. Then the loop needs to run through each term.

Below is my code. Commented out in green is some pseudo code that I am not sure what to do next.

Any guidance would be much appreciated.

pragma encoding, "UTF-8"
DB searchDB = create ("Search Utility", styleStandard)
DBE InfoTextDBE = text(searchDB, "Instructions", "Enter Search terms. Enter attribute name for column.", 200, 50, true)
DBE SearchTextDBE = text(searchDB, "Search terms", "", 200, 50, false)
Module m = current 
Object o = current
void searchFunction (DB win) 
                Buffer bufResults = create()
                string objectHeading, objectText, objectBoth
                string searchTerms[] = get SearchTextDBE
                //for the entire string entered in the text box 
                for (i=0; i<sizeof(searchTerms); i++) 
                   parse out each term separated by a comma 
                   save each term into an array 
                   bufResults += Terms[i]
                   then continue until the end of string
                for o in m do
                        //search both object text and headings
                        objectText = richText o."Object Text"
                        objectHeading = richText o."Object Heading" 
                        objectBoth = objectHeading " " objectText 
                        int offset = null
                        int length = null
                        bool matchCase = false
                        bool reverse = false
                        string Comma  
                        Comma = ", "
                        bufResults = ""
                        //loop through all terms in the array
                        for (i=0; i<sizeof(searchTerms); i++)
                         //Search all objects.
                         if (findPlainText (objectBoth, searchTerms[i], offset, length, matchCase, reverse))
                                bufResults += searchTerms[i]
                                bufResults += Comma
                                bufResults += "\n"
                                o."SearchTerm" = stringOf(bufResults)    //set the attribute to the term(s) found.
                                continue // Search remaining terms
void closeWindow (DB searchDB) 
hide (searchDB)
apply (searchDB, "Search Terms", searchFunction)
close (searchDB, true, closeWindow)
show searchDB
Updated on 2014-01-09T00:34:47Z at 2014-01-09T00:34:47Z by iron-man
  • llandale
    3035 Posts

    Re: Search menu


    I write code inside out; write the guts that does the work then add the loops and functions to support the guts.

    [1] Your guts should look like this:

    for (i=0; i<sizeof(searchTerms); i++)
       if (findPlainText (objectBoth, searchTerms[i], offset, length, matchCase, reverse))
       {  if (length(bufResults) > 0) then bufResults += Comma
          bufResults += searchTerms[i]
    o."SearchTerm" = tempStringOf(bufResults)    //set the


    • set the results at the end; even when no search terms were found
    • You don't need a comma AND an EOL
    • your "continue" at the bottom and also that null else clause look confusing to me.
    • I think I would use "matches" instead of "findPlainText".
    • I note term "shall" will match words "shallow" and "marshall". I think your terms are actually "words" in which case the "contains" command may help. I'll let other folks improve this weakness.

    [2] I think this object loop is better:



    for o in entire m do
    {  if (isDeleted(o))    continue

    This divorces your code from the current display set.

    [3] "arrays" (your searchTerms) are awkward to manage since you MUST define their size when they are declared. Using a Skip list is better:



    Skip skpTerms = createString()
    for each Term specified by user
    {  put(skpTerms, thisTerm, thisTerm)
        // now change your "guts" above:
    for Term in skpTerms do
    {  findPlainText bla bla bla

    If nothing else, this will sort out duplicate "Terms" the user may have specified.

    [4] Parsing. Seems to me there have been string parsing functions posted. Here is one so long as you use Delims of space, comma, EOL " ,\n". If your "terms" may have spaces in it then use delims of ",\n", but then strip the white space off start and end of your terms.



    string    fStripNextEntry(string &AttrVal, Delims)
    {            // Strip the next valid "Entry" from  the Attribute Value;
                    //      updating the remaining value.  "Entries" are separated by ANY of the
                    // Characters in the Delim variable (such as "\n").  The start and end of the
                    //      string are considered delimiters; thus a string with no Delims will return that string.
                    // This is useful when parsing an attribute that contains valid link
                    //      information, such as generated by "CaptureLinks.dxl" or "capture5.dxl".
                    // The calling program is advised to ignore null returned Entries, but
                    //      keep looping until the updated AttrVal is null. e.g.:
                    //              AttrVal         = fGetAttrVal(obj, NameAttr)
                    //              AttrValTemp     = AttrVal
                    //              while (!null AttrValTemp)
                    //              {  Entry     = fStripNextEntry(AttrValTemp, cl_Delims)
                    //                 if (null Entry) continue
                    //                 <Deal with valid 'Entry'>
                    //              }
                    // Note: user may want to set Delims to white space cl_White or cl_Delims.
            int     AttrValLength   = length(AttrVal)
            int     Offset, LenDelims       = length(Delims)
            int     iAttr, iDelim
            string  Entry, OutAttrVal
                            // Find the First Delim, ignore all others.
                            //      For each character in the AttrVal..
                            //         For each character in the Delims
                            //            Is Character same as Delim?
            Offset = -1
            for (iAttr=0; iAttr<AttrValLength; iAttr++)
            {  for (iDelim=0; iDelim<LenDelims; iDelim++)
               {  if (Offset == -1 and AttrVal[iAttr] == Delims[iDelim])
                  {  Offset = iAttr
               if (Offset >= 0) break
            }    // end looking for the next Delim
            if (Offset < 0)
            {            // No Delims in AttrVal.  Return entire AttrVal
               Entry        = AttrVal
               OutAttrVal   = ""
            }    // end no delims found
            {            // A Delim is Found
               if (Offset == 0)
                    Entry   = ""          // a Delim at start of AttrVal
               else Entry   = AttrVal[0:Offset-1]
               if (AttrValLength == Offset+1)
                    OutAttrVal      = ""          // the only Delim is at end of AttrVal
               else OutAttrVal      = AttrVal[Offset+1:]
            }    // end yes a delim found
            AttrVal = OutAttrVal    // DXL bug.  It seems modifying a call-parameter
                                            //   variable (AttrVal) in the middle of a function
                                            //   doesn't work.  So we stage the results (OutAttrVal)
                                            //   Instead.  Oh well.
    }    // end fStripNextEntry()

    I wrote that function 11 some years ago and perhaps I should do it more elegantly.



    Updated on 2014-01-09T00:37:00Z at 2014-01-09T00:37:00Z by iron-man