Advice on a string problem please?

I don't necessarily need help, just advice on the approach to take for a function I'm writing. I'm like a year in to C++ so please don't crucify me.
Here's the scenario: I'm working on a program that takes input from speech recognition and responds to various strings in different ways.

I've made tremendous progress filtering the strings but for it to be truly accurate I feel I need to iterate the string and match the words one at a time because speech recognition adds words to match every little sound..

Say the string is "number test command mode" and the words "test command" are the trigger phrase for a command, I could do something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using namespace std;
void process(string temp){
    istringstream iss(temp); 
    do{ 
	string word; 
        iss >> word; 
         if(word == "test"){ 
            bool var0 = 1;
         }
         if(word == "command" && var0 == 1){
            test command() //run the command that matches "test command"
            var0 = 0;
            return;  
         }
       // more sequential if statements following here 

     } while (iss); 
}
int main{
   string input = "number test command mode";
   process(input);
}


Naturally this would be ugly, and require another another if statement and unique bool for each word of every command in the program.

I've also considered pushing words into a vector and trying to match them by length but when I think about how that would work it seems like it could get even more tedious than the first way.

Any suggestions on how to maybe iterate a string through all the possible combinations of the words in it or something? Thanks for reading, Tom




wait what are you matching? Words or phrases? exact or misspelled?
Last edited on
Some of the commands are just one word, others are 2 words, so I suppose a phrase. The returned string from speech recognition is limited to the words I have in it's dictionary, which are all lower case and spelled correctly.

Essentially I need to compare one string to see if it matches numerous other strings
splitting it into words seems like the best start.
but you don't want to search it via brute force word by word, you want to search phrases.
That is, you need something that the first word leads to the second (or fail out) ... like a finite state machine, graph/tree, etc like structure.
I looked at sort(), maybe the method I first considered is simplest after all. There are approximately 15 different commands so that baby's gonna be a little long but here's an example with 4 functions.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
using namespace std;

void process(string temp){
bool var0, var1, var2, var3; //one bool for each command
    istringstream iss(temp); 
    do{ 
	string word; 
        iss >> word; 
        // search for phrase "test command"
         if(word == "test"){ 
            bool var0 = 1;
         }
         if(word == "command" && var0 == 1){
            test command();
            var0 = 0;
            return;  
         }
         // search for phrase "raise volume"
         if(word == "raise"){ 
           var1 = 1;
         }
         if(word == "volume" && var1 == 1){
            raisevolume();
            return;  
         }
         // search for phrase "lower volume"
         if(word == "lower"){ 
           var2 = 1;
         }
         if(word == "volume" && var2 == 1){
            lowervolume();
            return;  
         }
         // search for phrase "shut down"
         if(word == "shut"){ 
           var3 = 1;
         }
         if(word == "down" && var3 == 1){
            shutdown();
            return;  
         }

     } while (iss);
var0 = 0;
var1 = 0;
var2 = 0;
var3 = 0;
}
int main{
   string input = "number test command mode";
   process(input);
}
permutations leading to map/dictionary leading to relevant action
I was hoping to, figuring there was a way to break the string into words, then iterate through all possible combinations of words in the string, bouncing each single word and combination of words down a ladder of if statements to see if it == a command trigger string
Last edited on
Eh, 8 lines for each command. I just ran it and it's crazy accurate compared to what I was doing before so I guess ending up with a 150ish line long function is forgivable. I can always revise it later if a better method comes along.

Thank you guys for your suggestions....
PS L1 isn't what you want. You're defining a new variable var0 - not setting the existing variable with the same name.
If I'm not missing something, the words can be defined as either action or object. Action words define an action that is taken on an object. So 'raise volume' is the action raise on the object volume.

So if you define say an enum for each action and have a result value for each object, then when an action word is parsed then enum value is added to the action result. When an object is found then the required action is that of the action result. If you then have a separate function for each valid combination of action/object, then you can have an array of functions that are directly evaluated. Similar to againtry's method above.

Doing it something like this, when you want to add a new action/object all you need to provide is the required function(s) and expand the tables.
This more or less does what I had in mind. The challenge is to refine the use of the index to create the branch to the relevant function for a valid combination of words, and also to only have a <map> (or a <vector>).

There again a word (association + expectation) tree might be better -> how does Siri do it?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
#include <sstream>
#include <string>

#include <vector>
#include <map>

#include <algorithm>

int main()
{
    std::string word;
    std::vector<std::string> word_vector;
    std::map<std::string, int> word_map;

    // EXTRACT WORDS
    std::string input = "number test command mode";
    std::stringstream iss(input);
    while( iss >> word)
    {
        word_vector.push_back(word);
    }

    std::string temp;
    int index{0};

    for( int i = 0; i < word_vector.size() + 1; i++)
    {
        do{
            temp = "";

            for(int j = 0; j < i; j++)
            {
                temp += (word_vector[j] + ' ');
            }

            if(!word_map[temp])
            {
                word_map[temp] = index;
                index++;
            }

        }while(next_permutation(word_vector.begin(), word_vector.end()));
    }


    for(auto &i: word_map)
        std::cout << i.second << '\t' << i.first << '\n';

    return 0;
}

1
2 command
6 command mode
18 command mode number
42 command mode number test
19 command mode test
43 command mode test number
7 command number
20 command number mode
44 command number mode test
21 command number test
45 command number test mode
8 command test
22 command test mode
46 command test mode number
23 command test number
47 command test number mode
3 mode
9 mode command
24 mode command number
48 mode command number test
25 mode command test
49 mode command test number
10 mode number
26 mode number command
50 mode number command test
27 mode number test
51 mode number test command
11 mode test
28 mode test command
52 mode test command number
29 mode test number
53 mode test number command
4 number
12 number command
30 number command mode
54 number command mode test
31 number command test
55 number command test mode
13 number mode
32 number mode command
56 number mode command test
33 number mode test
57 number mode test command
14 number test
34 number test command
58 number test command mode
35 number test mode
59 number test mode command
5 test
15 test command
36 test command mode
60 test command mode number
37 test command number
61 test command number mode
16 test mode
38 test mode command
62 test mode command number
39 test mode number
63 test mode number command
17 test number
40 test number command
64 test number command mode
41 test number mode
65 test number mode command
Program ended with exit code: 0


Thank you guys for the suggestions, the againtry program is pretty close to what I was hoping to do, more than I was hoping to do actually as it reverses the order of the string.
Speech recognition hears what I'm saying in the correct order, it just adds additional words here and there.

I wrote it last night after my last post, in the slot machine manner I was toying with. it's a whole lot of if statements but I ended up with 23 commands in 190 lines and it hears much better now. I'll take some time and study the permutation program above for a re-write of my function, that method would be nice as a function itself since it could be useful in response selection as well. Thank you for taking the time to write that up.

I'm actually gearing up to do a few videos of the AI in a week or so, it's installed on a SBC in a robot modeled after Dr. Theopolis from Buck Rogers, the members of this forum have been a big help while I'm learning, I'll post a link when it's online so you guys can see what all these little functions have been leading up to.
@OP

FWIW there is an additional embellishment that would be easy to add. This would be a list of acceptable words that the initial string is checked against.
In other words you would end up with a list of phrases made up of acceptable words in any order.

Perhaps and embellishment to remove duplicated words in the initial string.
Haha! That's a great idea, I actually did that a while ago. So the initial filtering of the string is compared to a list of words in a file called "commands", when those are found they get appended to "std::string commandstring". This final function is only seeing commandstring.
There are a couple more files for responses and such. That was a giant step forward for this project.
Last edited on
againtry,

Once the command strings were taken care of with my "slot machine" method I did rework a bunch of your permutation code into a function to query regular chatbot responses and she's having the most accurate conversations she's ever had.
It was a little challenging as a novice but I figured out how to remove the single whitespace from the end of the string in a single line of code (she wasn't liking that whitespace) and the function ended up being only 27 lines. Thank you for showing me that, and thanks again for everybody's input.
Speech recognition has been an incredible uphill battle, It took me a couple of months to do hardware and write the first version of the program, and 8 months to get it to hear my voice with any level of accuracy.
:)
Topic archived. No new replies allowed.