tags:

views:

65

answers:

3

Friends, I want to read a pair of characters separated by \t. I want to continue reading the input until user enters z for any of the characters.

Here are the options I thought:

while (cin>>ch1>>ch2)
{

// process ch1 & ch2

}

std::string str;

while (getline(cin, str) ){

//split string

}

Also, I want to validate the input to make sure that it is correct. Please suggest the best way. If this is a duplicate, please point me to the right one.

Thanks.

+2  A: 

Your first approach is good and very C++ish. The only problem is that it will read chars not only separated by \t, but also, for example, by plain space ();

The code would look the following way:

#include <iostream>

void main () {
   char c1, c2;
   while (std::cin >> c1 >> c2) {
      if (c1 == 'z' || c2 == 'z') break;
      // Otherwise do something useful
   }
}

Alternative approach is using getche() to take one symbol from input and show it on the screen. Here's the code:

#include <iostream>
#include <conio.h>

void main () {
   while (true) {
      char c1 = getche();
      char delimiter = getche();
      char c2 = getche();

      // Output end of line
      std::cout << std::endl;

      if (delimiter != '\t' || c1 == 'z' || c2 == 'z') break;
      // Otherwise do something useful
   }
}

Note that right now you don't have to press enter key after entering sequence. If you want to, you could add one more getche() call and check if the char equals 32 (enter code).

Kotti
Generally speaking, your second approach is also fine, but requires additional body movements that parse string and, therefore, isn't recommended for such kinds of input sequences.
Kotti
I don't think `<conio.h>` is a standard header.
sbi
I agree, but sometimes it's pretty useful (just to simplify writing of trivial console parsers)
Kotti
+3  A: 

Despite its name, you can use std::getline() to read other things than lines. It takes an optional third parameter denoting the delimiter. The default one is '\n', but there's no reason you cannot use '\t' instead.

std::string line;
while( std::getline(is,line) ) { // read lines
  std::istringstream iss(line); 
  std::string field;
  while( std::getline(iss,field,'\t') { // read fields from line
    // process field
  }
}
sbi
Isn't that a waste to create 2 strings and an additional istringstream object to parse 3-char console input? :)
Kotti
@Kotti: That might well be, but... For one, using `std::getline()` is definitely the easiest way to do this right. And then - why optimize a piece of code that waits for input from a user (or disk, which doesn't make all that much difference)? __If__ this code is ever found to be to slow (which I very much doubt), then it could always be replaced by optimized code later. Until then, readable and bug-free code rules.
sbi
@sbi Ok, +1 :))
Kotti
I'm not sure what I should make of the fact that for two hours nobody noticed that my second call to `std::getline()` missed the `'\t'` parameter...
sbi
+1  A: 
int main(int argc, char* argv[])
{
    char c;
    int count = 0;
    string s; // s.reserve(LOTS);
    while(cin) while( cin.get(c) ) { // consume newlines as well
        if( c == '\t' ) continue;
        if( c == 'z' ) break;
        ++count;
        s += c;
    }
    cout << "got " << count << " tokens." << endl;
    cout << s << endl;
    return 0;
}
wilhelmtell