Idiot-proof Yes/No Input

Pages: 123
When faced with a yes/no choice, the user can sometimes use something completely oddball at you such as "Yeah, sure," "Ok, why not," or "Heck no," which will throw my program into an infinite loop. I am trying to create a reusable function that will check through as many incarnations of yes and no as I can think of, then return 0 if no is detected, 1 if yes, and 2 if other. After some brainstorming, I decided I want the function to first strip an input string of special characters, then convert everything to lowercase to prepare the string for analysis. Then the string would be checked for the most common "1/0", "T/F", "y/n", etc., before going through the stranger input possibilities. If no match is found, it should return 2 so the program can know to ask for input again.

To do this, I am wondering how to separate a string into words. I had thought about locating all spaces in a string and extract all words in between them to be checked, but I am unsure how to do this. Can someone show me how?
I think you're looking for the strtok() function.

Check it out here.... http://www.cplusplus.com/reference/clibrary/cstring/strtok/
Argh. Please don't.

First, require your user to answer with a clear YES or NO. For more general purpose things, you can easily take any concrete boolean answer. The common ones are, of course:
  yes
  true
  1 (you may also wish to consider non-zero numeric values as 'true')
and:
  no
  false
  0
If the user answers something that is not valid, ask him to type a clear YES or NO.

What follows is a variation on my Select on a String example (found here http://www.cplusplus.com/forum/general/11460/#msg54095 as the second [code] block)
 
...

I have to pick my son up from school. I'll post back later.
Duoas:
I don't have that much faith in people. Heck, people get confused about where the any key is from "Press any key to continue." and I really think that even clearly asking for just a YES or a NO would not work all the time.


I am going to try the strtok() method, it seems to be working well so far.
++Duoas
I agree with Duoas. Accept "yes"/"no" and "y"/"n" in any combination of case, but nothing else. "Input validation" doesn't mean "decipher the meaning of every conceivable input". It means "verify that the input matches a limited set of patterns, and reject it if it doesn't".
y/n makes so much sense and it's just one other character. What other methods do you need?
I generally take an explicit y as yes and anything else as no but you can error check if you want to be clearer.
Although should you choose to, as a kind of goal or something, you could make a small AI that understands various yes and no inputs but for a simple program y/n works wonders.
Alright, here's the code I wrote for you.
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <algorithm>
#include <cctype>
#include <functional>
#include <sstream>
#include <string>

/* string_to_boolean()
 *
 *   Convert a string into its boolean value.
 *   The string MUST BE one of:
 *     "TRUE" "FALSE" "YES" "NO" "0" "1"
 *   or a numeric value. Case is not significant.
 *
 *   Numeric values evaluate to FALSE if they equal zero; TRUE otherwise.
 *
 *   If the conversion is STRICT then numeric values are limited to 
 *   the strings "0" and "1".
 */

typedef enum
  {
  boolean_false,
  boolean_true,
  boolean_invalid
  }
  string_to_boolean_t;

string_to_boolean_t
string_to_boolean( const std::string& s, bool strict = false )
  {
  const char* falses[] = { "false", "no",  "0" };
  const char* trues [] = { "true",  "yes", "1" };

  unsigned num_falses = sizeof( falses ) / sizeof( falses[ 0 ] );
  unsigned num_trues  = sizeof( trues  ) / sizeof( trues [ 0 ] );

  // Special case
  if (s.empty()) return boolean_invalid;

  // Get a lowercase version of 's'
  std::string s2( s );
  std::transform(
    s2.begin(),
    s2.end(),
    s2.begin(),
    std::ptr_fun <int, int> ( std::tolower )
    );

  // Does the string represent a FALSE?
  for (unsigned n = 0; n < num_falses; n++)
    if (std::string( falses[ n ] ).find( s2 ) == 0)
      return boolean_false;

  // Does the string represent a TRUE?
  for (unsigned n = 0; n < num_trues; n++)
    if (std::string( trues[ n ] ).find( s2 ) == 0)
      return boolean_true;

  // Check for non-zero numbers here
  if (!strict)
    {
    std::istringstream ss( s2 );
    double d;
    if (ss >> d)
      return (d == 0.0)
           ? boolean_false
           : boolean_true;
    }

  // The string was not recognized
  return boolean_invalid;
  }
And something to show it in action.
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include <iostream>
using namespace std;

int main()
  {
  cout << "Did this work for you? " << flush;
  string s;
  getline( cin, s );

  switch (string_to_boolean( s ))
    {
    case boolean_false:   cout << "NO? What!?\n";      break;
    case boolean_true:    cout << "Of course. :-)\n";  break;
    case boolean_invalid: cout << "Hey! YES or NO.\n";
    }

  return 0;
  }

Be sure to play with the strict option.

Also, since you've posted back with drivel (sorry), being "forgiving" implies more faith in good inputs. Be strict! If your user cannot answer with a clear YES or NO then he has no business frobbing your keyboard.

Also, the famous "Press any key to continue" really is a dumb instruction. It should be "Press ENTER to continue" or "Press a key to continue". The first is unequivicably explicit, and the second is forgiving of people who think the instruction was to press the A key.

Part of programming any user interface (whether GUI or textual) is recognizing that your users have different memes than you do about the way the computer works. Your program must cater to their expectations.

Hope this helps.
I still don't, and probably never will, understand how someone could interpret a determiner as a proper noun.
Nor do I, but apparently it is a common problem with users.

I remember reading a comic once where something like the following (not too farcical scenario) occurred:

"Press any key to continue"
<user presses A>
"Would you like to save before quitting?"
<user, still looking at keyboard, presses N>
"Are you sure?"
<user, still looking at keyboard, presses Y>

I wish I could remember where I saw it.
You know? If someone is stupid enough to do that, they have no business using a computer. There's really no telling what someone like that would interpret from any given message. "Press ENTER..." or "press a key..." wouldn't have helped much.
closed account (z05DSL3A)
Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.
I made a function a while ago, it's nowhere near as complex as Duoas' but it works for me.

I'll post it if you want, later. I'm still at school, doing 'work'.

Note: it is a C implementation; so you'll probably want to change alot of things.

@Grey Wolf,
I had to laugh at that quote.
Last edited on
Cute quote. (Really, it is amusing.)

But, under the surface:

I think it is a little presumptous (though common) for us to think of users as "stupid" (or "idiots"). They do "stupid" things, because they don't know any better.

I mentioned memes. We know how to respond to things like "Press any key" because we have been taught --if not about that specific phrase then we have been taught the proper way to read such a sentence. A programmer's education necessarily involves some degree of formal, analytically logical thinking.

Most people's don't.

As a result, they view our way of thinking as confusing and, oddly enough, illogical. Yes, our logic does not wholly intersect with their logic.

Now before anyone spouts off with "there's only one true logic" let me say, from a highly-educated pov, bull-pucky. There are many logics, some with greater use than others. Every logic exists because it validates a specific way of understanding things. A simple enough example is that programmer's logic is not conducive to being a suit. Said programmer must first learn "suit logic."

I just gave another example. A normal programmer would have written "suit logic". (Compare locations of the full-stop/period.) But the MLA and APA say it belongs inside the quotes. The correct choice is not absolute. The correct choice depends on context. If I were writing a manual, I'd keep periods out of quotes. If I were writing a paper, I'd use MLA or APA.

Oh, and please, please, do not generalize this to the way the universe works. All it is is the way people understand things. And it is certainly true that the way a person understands a thing may very well be incorrect. Hence, the high incidence of programming bugs and user errors. Hmm, it seems that both programmers and users get it wrong, often enough.


This is the reason UI design is so feared. The UI designer needs to live with both logics -- the programmer's logic and the user's logic. Having spent so much time and energy to learn the programmer's logic, most programmers allow it to supplant user's logic -- and so we see it as "stupid." The user, likewise, sees the programmer's logic as "stupid." After all, why won't program A do what I want when program B does? What the heck do all those template error messages mean anyway? We programmers need tools just to decipher them...

The fundamental error is applying the wrong logic in the wrong situation. That is easy enough to do if you don't know the correct logic for a situation, which is frighteningly common in real life.

/end rant
I sort of understand what you're getting at, Duoas. Ok, no, most users are not necessarily "stupid," but to be [un]fair, before I got into programming I knew that "Press any key" meant "Press a key of your choice." (Compare locations of the full-stop/period.)

Although that may be because I had already started to develop this "programmer's logic" you speak of.
Last edited on
Duoas, all that is fine and good, but I think there's a world of difference between expecting a user to know what "wait for the HDD to spin-up the I/O algorithmic sorter and kill the power" means and expecting them to have a basic grasp of reading comprehension.

But the MLA and APA say it belongs inside the quotes.
AFAIK, there's no general consensus on that matter. "." is the "American" style, and "". is the "British" style, but neither is exclusive to either region, or used exclusively in any context.
I use what you call "the American style" and AFAICR, always have. I've been taught that way.

Oh, and someone told me today that because I pronounce "pronunciation" as pro-nun-see-a-shon instead of pro-noun-see-a-shon (which is apparently wrong, even though it's spelled "pronunciation" in both English and "American English") I must be "American."
I use both pro-noun-see-a-shun and pro-nun-see-a-shun and my spell checker isn't going crazy with the sounding out of words ... fishy ...
Pages: 123