简体   繁体   中英

Using wildcards or “tags” for user input

I've recently begun learning C# with no prior programming experience. I've been going through tutorials and I'm learning about "if" statements. I am trying to create a simple user feedback application that asks questions and responds to user input.

What I'd like to do is use some kind of keyword or tag system or a wildcard-type system (like the * in search queries) to allow a response to input that isn't exactly specific.

For example, in the following code, where I use the If and Else statements, is there a way to set the userValue equal to not just "good" or "bad" but to any number of variations on both those words, (eg "I'm quite good.") or have the If statement refer to a list of keywords or tags, (perhaps listed elsewhere, or in an external file) so that the user can input however they feel, and the predetermined program will pick up on the phrase.

I'm not looking to create some form of AI, only to make a fun responsive program. Would it be possible/sensible to use an array, and somehow invoke it as an If statement? Or is there another, more effective method, to provide feedback to user input? I'm sorry if this is too newbie-ish for this site. I've searched the internet, but the problem is, I don't exactly know what I'm searching for!

The code I have so far is as follows:

Console.WriteLine("Hello. How are you?");
        string userValue = Console.ReadLine();

        string message = "";

        if (userValue == "good")
            message = "That's good to hear. Do you want a cup of tea?";

        else if (userValue == "bad")
            message = "I'm sorry to hear that. Shall I make you a coffee?";

        else
            message = "I don't understand. Do you want a cuppa?";

        Console.WriteLine(message);

        string userValueTwo = Console.ReadLine();

        string messageTwo = "";

        if (userValueTwo == "yes")
            messageTwo = "I'll get right onto it!";

        else if (userValueTwo == "no")
            messageTwo = "Right-o. Shutting down...";

        Console.WriteLine(messageTwo);

        Console.ReadLine();

You can use regular expressions here:

using System.Text.RegularExpressions;

...

// If the phrase stats/ends or contains the word "good"  
if (Regex.IsMatch(userValue, @"(^|\s)good(\s|$)", RegexOptions.IgnoreCase)) {
  message = "That's good to hear. Do you want a cup of tea?";
}

I hesitated to post this answer, since it uses LINQ which may confuse you given that you're only just learning. It's simpler than scary regular expressions though! You could do this using your own loops, but LINQ just saves you some code and makes it (arguably) more readable:

Console.WriteLine("Hello. How are you?");
string userValue = Console.ReadLine();

string message = "";

string[] goodWords = new string[] { "good", "well", "sweet", "brilliant"};
string[] badWords  = new string[] { "terrible", "awful", "bad", "sucks");

if (goodWords.Any(word => userValue.Contains(word)))
    message = "That's good to hear. Do you want a cup of tea?";

else if (badWords.Any(word => userValue.Contains(word)))
    message = "I'm sorry to hear that. Shall I make you a coffee?";

else
    message = "I don't understand. Do you want a cuppa?";

Basically the Any() function sees if there are any words in the list that match some criteria. The criteria we use is whether the userValue string Contains() that word. The funny looking => syntax is a lambda expression , just a quick way of writing an anonymous function. Again, something that may be a bit too confusing right now.

Here's a non-LINQ version which you may find easier to understand:

void main()
{
    Console.WriteLine("Hello. How are you?");
    string userValue = Console.ReadLine();

    string message = "";

    string[] goodWords = new string[] { "good", "well", "sweet", "brilliant"};
    string[] badWords  = new string[] { "terrible", "awful", "bad", "sucks"};   

    if (DoesStringContainAnyOf(userValue, goodWords))
        message = "That's good to hear. Do you want a cup of tea?";

    else if (DoesStringContainAnyOf(userValue, badWords))
        message = "I'm sorry to hear that. Shall I make you a coffee?";

    else
        message = "I don't understand. Do you want a cuppa?";

    string answer = "I'm really well thanks";        
}

bool DoesStringContainAnyOf(string searchIn, string[] wordsToFind)
{
    foreach(string word in wordsToFind)
        if (searchIn.Contains(word))
            return true;

    return false;
}

How about a simple Contains check?

if (userValue.ToLower().Contains("good"))

I also added ToLower() case conversion so that it would work regardless of the case.

If you wanted to implement a list of keywords and programs (functions), I would do it somewhat like that:

var keywords = new Dictionary<string, System.Func<string>>() {
    { "good", () => "That's good to hear. Do you want a cup of tea?" },
    { "bad", () => "I'm sorry to hear that. Shall I make you a coffee?" }
};

foreach(var keyword in keywords)
{
    if (userValue.ToLower().Contains(keyword.Key))
    {
        message = keyword.Value();
        break;
    }
}

In this case, I use C# lambda expressions to save the "list of programs" you wanted; it's a pretty powerful C# feature that allows to use code as data. Right now these functions just return constant string values, so they're a bit of an overkill for your scenario, though.

Try using the "Contains" method. http://msdn.microsoft.com/en-us/library/dy85x1sa(v=vs.110).aspx

Example:

if (userValue.ToLower().Contains("good"))
        message = "That's good to hear. Do you want a cup of tea?";

All previous answers are valid and contain many things well worth learning. I want to draw special attention to the lower method, which will help you to recognize both, 'Good' and 'good'.

Also, to make the list more complete, you should know about the good old IndexOf method, which will return the place of a substring within a string, or -1 if it isn't contained there.

But I have a hunch that your question also targets the problem of how to write the Eliza code (which of course is the name of the game) in a more effective way. You surely want more than 2 questions..?

It is most fun if the cue words and the responses can easily be expanded without changing and compiling the program again.

The easiest way to do that is to put all data in a text file; there are many ways to do that, but easiest maintance comes with a line-by-line format like this:

//The text file eliza.txt:

good=That's good to hear. Do you want a cup of tea?
bad=I'm sorry to hear that. Shall I make you a coffee?
father=Tell me more about your family!
mother=What would you do Daddy?
..
bye=Goodbye. See you soon..

This is read in with the File.ReadLines command. Add a using System.IO; to the top of your programm if it isn't there already.. From there I suggest using a Dictionary<string, string>

    Dictionary<string, string> eliza = new Dictionary<string, string>();
    var lines = File.ReadAllLines("D:\\eliza.txt");
    foreach (string line in lines)
    {
        var parts = line.Split('=');
        if (parts.Length==2) eliza.Add(parts[0].ToLower(), parts[1]);
    }

Now you could create a loop until the user says 'bye' or nothing:

    string userValue = Console.ReadLine();
    do
    {
        foreach (string cue in eliza.Keys)
            if (userValue.IndexOf(cue) >= 0)
            { Console.WriteLine(eliza[cue]); break; }
        userValue = Console.ReadLine().ToLower();
    }
    while (userValue != "" && userValue.IndexOf("bye") < 0);

Fun things to expand are lists of cue words, lists of reponses, removing some responses after they have been used or throwing in a few random responses..

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM