zoey xeen
zoey xeen

Reputation: 21

C++ Dots as spaces?

Let's say I have

int a; cin >> a;   
int b; cin >> b;
int c; cin >> c;  

I would like to know how I can get same results from both inputs:

1.2.3 and 1 2 3

so that a would be 1, b would be 2 and c would be 3 if I input 1.2.3

Upvotes: 2

Views: 652

Answers (4)

Thomas Matthews
Thomas Matthews

Reputation: 57749

You could read the text as a string, replace the '.' with space, then use std::istringstream to convert to numbers:

std::string text_read;
std::getline(cin, text_read);
std::string::size_type position = text_read.find('.');
while (position != std::string::npos)
{
  text_read[position] = ' ';
  position = text_read.find('.');
}
int a;
int b;
int c;
std::istringstream text_stream(text_read);
text_stream >> a;
text_stream >> b;
text_stream >> c;

This is a brute force technique. You may be able to optimize using std::transform.

Upvotes: 0

2785528
2785528

Reputation: 5576

This post is marked as C++.

Here is some C++ to consider:

#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <cassert>

// forward 

// stream input, extract and discard junk char
void trial1(std::string s);     

// stream input, ignore() junk char,
//   with error check for each integer input
void trial2(std::string s); 

// sscanf of string
void trial3(std::string s); 



int main(int , char** )
{
   std::cout << "\n";  // stream input, extract and discard junk char
   trial1("1.2.3");
   trial1("1,2,3");
   trial1("1 2 3");    // fail


   std::cout << "\n";  // stream input, ignore junk char, error checks
   trial2("1.2.3");
   trial2("1,2,3");
   trial2("1 2 3");
   trial2("11.12.13");
   trial2("111,222,333");
   trial2("1234 1234 1234");
   trial2("1234 -12345678 1234");
   trial2("1x2y3");
   trial2("1xx2yy3");    // fail - ignore skips 1 char, not 2


   std::cout << "\n"; // sscanf of std::string
   trial3("1.2.3");
   trial3("1 2 3");
   trial3("1,2,3");
   trial3("111,222,333");
   trial3("1234 -12345678 1234");
   trial3("1234,1234,1234");
   trial3("1xx2yy3");    // fail 


   std::cout << "\n";  // requirements?
   trial1("foo bar");
   trial2("foo bar");
   trial3("foo bar");
}


void trial1(std::stringstream& sin)
{
   char junk;
   int a = -1;  sin >> a >> junk;
   int b = -1;  sin >> b >> junk;
   int c = -1;  sin >> c >> junk;

   std::cout << " -->  " << a << " " << b << " " << c;
}
void trial1(std::string s)
{
   std::cout << '\n' << __FUNCTION__ << "  '" << s << "'";
   std::stringstream sin (s);
   trial1(sin);
}


void trial2(std::stringstream& sin)
{
   int a = -1;
   int b = -1;
   int c = -1;

   do{
      sin >> a;
      if(!sin.good() && !sin.eof()) // check for error
         std::cerr << "  error on a " << std::flush;

      sin.ignore();   // ignore 1 char

      sin >> b;
      if(!sin.good() && !sin.eof()) // check for error
         std::cerr << "  error on b " << std::flush;

      sin.ignore();

      sin >> c;
      if(!sin.good() && !sin.eof()) // check for error
         std::cerr << "  error on c " << std::flush;

   }while(0);

   std::cout << " -->  " << a << " " << b << " " << c;
}
void trial2(std::string s)
{
   std::cout << '\n' << __FUNCTION__ << "  '" << s << "'";
   std::stringstream sin (s);
   trial2(sin);
}



void trial3(std::string s)
{
   std::cout << '\n' << __FUNCTION__ << "  '" << s << "'";
   int a = -1;
   int b = -1;
   int c = -1;    // note added ','----v---------v
   if (std::sscanf(s.c_str(), "%d%*1[ .,]%d%*1[ .,]%d", &a, &b, &c) == 3)
      std::cout << " -->  " << a << " " << b << " " << c;
   else
      std::cout << " -->  " << a << " " << b << " " << c << "         FAILED." << std::flush;
}

with output:

trial1  '1.2.3' -->  1 2 3
trial1  '1,2,3' -->  1 2 3
trial1  '1 2 3' -->  1 3 -1

trial2  '1.2.3' -->  1 2 3
trial2  '1,2,3' -->  1 2 3
trial2  '1 2 3' -->  1 2 3
trial2  '11.12.13' -->  11 12 13
trial2  '111,222,333' -->  111 222 333
trial2  '1234 1234 1234' -->  1234 1234 1234
trial2  '1234 -12345678 1234' -->  1234 -12345678 1234
trial2  '1x2y3' -->  1 2 3
trial2  '1xx2yy3'  error on b   error on c  -->  1 0 -1

trial3  '1.2.3' -->  1 2 3
trial3  '1 2 3' -->  1 2 3
trial3  '1,2,3' -->  1 2 3
trial3  '111,222,333' -->  111 222 333
trial3  '1234 -12345678 1234' -->  1234 -12345678 1234
trial3  '1234,1234,1234' -->  1234 1234 1234
trial3  '1xx2yy3' -->  1 -1 -1         FAILED.

trial1  'foo bar' -->  0 -1 -1
trial2  'foo bar'  error on a   error on b   error on c  -->  0 -1 -1
trial3  'foo bar' -->  -1 -1 -1         FAILED.

Upvotes: 1

Daniel Gale
Daniel Gale

Reputation: 663

You could use getline() to get the whole input and strtok() to tokenize the string. You may need to validate input etc. Here is an example.

#include <iostream>
#include <string.h>
using namespace std;

void DoSomething(char* inputChar){
    printf("%s\n", inputChar);
}

int main() {
    char myInput[256];
    char* pch;
    char* delimiters = " .";

    //Loop Through Input
    while (cin.getline(myInput,256)) {
        cout << "-" << myInput << endl;
        pch = strtok(myInput, delimiters);
        while (pch != NULL){
            //Individual input chars here
            DoSomething(pch);
            //Set NULL to find next delimited set of char
            pch = strtok(NULL, delimiters);
        }
    }
    return 0;
}

Try it now!

You can modify the delimiter list and whether or not to store or do something else with the inputs. Obviously getline() could be taken out of the outer while() if you only need to use it once. atoi() can try to cast the char* to int for you as well.

I used input

1 2 3
1.2.3
1

Upvotes: 0

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 727047

You can do it with std::scanf:

if (std::scanf("%d%*1[ .]%d%*1[ .]%d", &a, &b, &c) == 3) {
    ... // Input was successful
}

The tricky part is this for mat specifier: %*1[ .] It scans and ignores a single space or a single dot.

Demo.

Upvotes: 6

Related Questions