Have an idea?

Visit Sawtooth Software Feedback to share your ideas on how we can improve our products.

Shorten TextExist function code

Hi,

I want to show a question based on the existence of a word and its spelling varieties (eg Apple, Aple, Appl etc). I have made the code logic to work but the code looks lengthy. I want this code to be shortened so that I can add any other words in future without any complications.
<input type="hidden" name="Q1H_A" value="

[%
Begin Unverified Perl
  if (TEXTEXISTS(VALUE("Q1_A"),"Apple")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_A"),"Aple")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_A"),"Appl")==1)
   {
    return 1;
   }

  else
   {
   return 0;
   }

End Unverified

%]
">


I tried the following code but it doesn't work

if (TEXTEXISTS(VALUE("Q1_A"),"Apple","Aple","Appl")==1)
asked Jul 3, 2017 by Abdul Bronze (1,540 points)
retagged Jul 3, 2017 by Walter Williams

2 Answers

+2 votes
 
Best answer
My attempt to shorten up the script and make it more expandable:

[% Begin Unverified Perl
my $val = GETVALUE('Q1_A');
my @words = ('Apple', 'Aple', 'Appl');
foreach my $word (@words) {
    if (TEXTEXISTS($val, $word)) {
        return 1;
    }
}
return 0;
End Unverified %]


If you want to support a large number of spelling variations, that code can become unwieldy and may have performance problems, as Paul suggested.  Regular expressions are a more advanced tool, but are what I would recommend looking into for these advanced string comparisons.  This code looks for "Apple" with one or two 'p' characters and an optional 'e' character:

[% Begin Unverified Perl
if (GETVALUE('Q1_A') =~ /App?le?/) {
    return 1;
}
return 0;
End Unverified %]


If you know what variations you need to support, I can help create a regular expression up to the task.
answered Jul 3, 2017 by Zachary Platinum Sawtooth Software, Inc. (67,750 points)
selected Jul 5, 2017 by Abdul
Nice one Zachary. Real neat solution!

I must admit, I'm not a fan of skips and conditions based on text fields that are littered with spelling errors. I try to talk the clients out of it actually.

And let's be honest, the respondents find new ways of spelling some of these words? Even a regular expression may struggle.

Thanks for chipping in again. Always welcoming to hear your opinion on such matters.

Thanks mate.
Yeah, automatically parsing information from text is far from a solved problem.  The misspelled "Appel" or misclicked "Appke" come to mind as examples of words my regex would not find.  Non-open end fields are certainly a lot safer with regard to human error.
Thanks Zachary for your response.
These are the variations my client has given as of now.
Pyxis, Pyxus, Pyxix, Pxyix, Pixis, Pixus
List may increase as this study is a tracker.
Also I have 4 open end text boxes in Q1 (Q1_A, Q1_B, Q1_C, and Q1_D) with first box is mandatory.
is loop enough for these variations or regular expression is required?
I am not interested in expression as I need to seek for it when a new word comes in as this study is tracker.
Can I continue with my current code rather than performance problem loop or seeking for regular expression.
Your suggestion?
Below is my complete set of coding
<input type="hidden" name="Q1H_A" value="

[%
Begin Unverified Perl
  if (TEXTEXISTS(VALUE("Q1_A"),"Pyxis")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_A"),"Pyxus")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_A"),"Pyxix")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_A"),"Pxyix")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_A"),"Pixis")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_A"),"Pixus")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_B"),"Pyxis")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_B"),"Pyxus")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_B"),"Pyxix")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_B"),"Pxyix")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_B"),"Pixis")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_B"),"Pixus")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_C"),"Pyxis")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_C"),"Pyxus")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_C"),"Pyxix")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_C"),"Pxyix")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_C"),"Pixis")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_C"),"Pixus")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_D"),"Pyxis")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_D"),"Pyxus")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_D"),"Pyxix")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_D"),"Pxyix")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_D"),"Pixis")==1)
   {
    return 1;
   }
  elsif (TEXTEXISTS(VALUE("Q1_D"),"Pixus")==1)
   {
    return 1;
   }
  else
   {
   return 0;
   }

End Unverified

%]
">
Loops will probably be sufficient for you.  You can test the performance yourself by trying "Pixus" in Q1_D.  Because that is the last string test, it should give you an idea of the maximum amount of time the code will take to run.

You can use my foreach loop four times to represent your four questions, or use this modified code with nested loops:

[% Begin Unverified Perl
my @questions = ('Q1_A', 'Q1_B', 'Q1_C', 'Q1_D');
my @words = ('Pyxis', 'Pyxus', 'Pyxix', 'Pxyix', 'Pixis', 'Pixus');
foreach my $question (@questions) {
    foreach my $word (@words) {
        if (TEXTEXISTS(GETVALUE($question), $word)) {
            return 1;
        }
    }
}
return 0;
End Unverified %]
Thank you so much Zachary. I will let you know in case of any concerns regarding this.
0 votes
Abdul, does this solution appeal to you?

Paste the full list of words into a parent list and call it WordList.

Now create a constructed list called WordConList which uses the WordList as the parent list.

Insert this Perl script into your constructed list ...
Begin Unverified Perl
 
 my $i=1;
 
 for($i=1; $i<=LISTLENGTH("WordList"); $i++)
  {
   if (VALUE("Q1_A") eq LISTLABEL("WordList",$i))
    {  
     ADD("WordList",$i);
     last;
    }  
  }
 
End Unverified

So what we have happening here is your constructed list is matching the Q1_A response with the full list of words stored in WordList. When it finds a match, it stores it in the WordConList constructed list and exits the for loop.

Now apply this skip condition in your termination skip ...

ListLength(WordConList)=0

This says if the constructed list (WordConList) is empty, there were no matches and therefore skip.

Note 1: The beauty of this script is you will never have to edit it, unless you change question names and/or list names. You only need to update WordList with the new list of words.
Note 2: If WordList becomes large, it can slow your survey down. I am assuming your list is not overly large.

Regards.
answered Jul 3, 2017 by Paul Moon Platinum (57,565 points)
Thanks Paul for taking time to reply. I am going with Zachary's solution which is very easy to update.
All good Abdul. The main thing is your problem is taken care of.

To have a number of solutions is better than one. Plus Zachary has some great ideas.

Good luck with the survey mate.
...