Variable in expression

Post your questions and help other users.

Moderator: Martin

Micky Micky
Posts: 179
Joined: 16 Oct 2019 17:38

Re: Variable in expression

Post by Micky Micky » 01 Jan 2020 13:48

So the hotword triggers it.
You then say something.
You then check to see if what you said is about meditating.
This is where your error is.
You are checking for a variable in the string. However, what is being checked is what is written literally. It will always return false. Because the number of minutes isn't always the same I think regex may help but I don't know how. My understanding of regex is limited to what I posted earlier.

Or you could check if the string contains the start
i.e. 'meditate for' and then extract the number of minutes. It's unique enough to be sure that's it's the right message. You could check the end too.

Good luck and Happy New Year
Crude but it works.

User avatar
Desmanto
Posts: 2709
Joined: 21 Jul 2017 17:50

Re: Variable in expression

Post by Desmanto » 01 Jan 2020 14:07

The hardest part of creating voice command database is to get the word recognized properly. I just try your wording, and it seems to be recognized properly with minimum ambiguation. So let's assume the wording is : "meditate for 30 minutes"

The next part is to catch the changing variable, which is the '30'. You can't use that expression to extract '30' from the recognize sentence. You must use regex to get perfect match, because it ensure it match all other words first, before extracting the number.

1. Copy "meditate for 30 minutes", go to the regular expression tester in action script. Paste it at the example text and Regular expression field.

Code: Select all

meditate for 30 minutes
You will see a perfect match as the result (Result covered in green). If you change the example text to "meditate for 20 minutes", you will see now it doesn't match anymore.

2. So we have to replace the "30" in the regex field, to the regex pattern which catch digit number. Since the number can be several digit, we can change it to \d+

Code: Select all

meditate for \d+ minutes
\d match digit, and + denote 1 or more character. So \d+ means 1 or more digits. (For all regex pattern meaning, see the help section at the regex tester.)

3. But now this match the whole text and you want only the "30", the number. You have to define a capture group, so it only capture that number. Add bracket to the \d+

Code: Select all

meditate for (\d+) minutes
Now you have 1 capture group. You can see the match part have group[0] and group[1]. i usually don't use the matches() because I usually have longer text that will result in false. So I always findAll() with the true argument (the second findAll() ).

4. Copy the script from the second findAll() and paste it into your expression. Replace the first argument with the variable of you want to test the regex, which is {value}.

Code: Select all

find = findAll(value, 'meditate for (\\d+) minutes', true);
5. This result the whole capture into a new list, along with the capture group in the second element and so on. We only have 1 line of text here, so it always result in first level only 1 element. To access the capture group 1, you have to retrieve index 1. (use debug dialog to understand the structure of the capture group)

Code: Select all

find = findAll(value, 'meditate for (\\d+) minutes', true);
minute = find[0][1];
6. Use {minute} in your calculation later.

Code: Select all

meditateduration = getDurationString(minute*60000)
Or you can simply put {getDurationString(minute*60000)} directly into the Set Timer - Duration field.

You can repeat the same thing for other regex pattern, replace the part you know it will be a variable with the proper pattern. And you can extract any chars from any sentences.


Protecting from error
However this have some problem with matching part. If you say a command and it doesn't properly match (example : "The answer to life is 42"), the line minute = find[0][1] will result in error, since {find} is empty. So you have to protect it by using if()

Code: Select all

if(!isEmpty(find))
  minute = find[0][1];
But then if the result is empty, the {minute} after it also will be null. So I usually just combined it into the same expression as the operation check. This will be the final expression.

Code: Select all

if(operation == "ok")
{
  find = findAll(value, 'meditate for (\\d+) minutes', true);
  if(!isEmpty(find))
 {
    minute = find[0][1];
    return true;
 }
  else return false;
}
return false;
True, continue to your calculation of duration. False, do nothing. This will ensure the flow only continue if the input dialog give result, and then result is properly match to the regex. This is also why I have so many expressions just to check the recognized command, because there are multiple check need to be done to ensure correct input speech.

PS : there is shorter expression for above one, but I prefer not to confuse you for now.
Index of Automagic useful thread List of my other useful posts (and others')
Xiaomi Redmi Note 5 (whyred), AOSP Extended v6.7 build 20200310 Official, Android Pie 9.0, Rooted.

coconutxyz
Posts: 38
Joined: 16 Sep 2019 12:51

Re: Variable in expression

Post by coconutxyz » 05 Jan 2020 05:42

thanks desmanto, i myself need some time to digest all this information lol

Post Reply