简体   繁体   中英

How can i read an unknown number of integers until space character is reached ? (C++)

I need to read numbers from console separated by ;until i get to the space character. The input should look something like this: 3;1 -2;-1;1 1;1;3;2 . There can by more than one space between each set of numbers and i need to insert each set of numbers into a vector . My initial ideea was something like this:

char c;
std::vector<double> coordinates;
while(std::cin >> c){
    if(c != ' ' & c != ';'){
        double a = c - 48;
        coordinates.push_back(a);
    }
}

The problem with this is that converting a char to an integer using ASCII can't be made if I have negative numbers. If anyone could give me another method to do this type of reading or can give me some advice I would appreciate it very much!

here's the code to do what you want
you can get the idea you wanted from it
don't forget to read comments
i also added char 'e' to end input

#include <iostream>
#include <vector>
#include <string>
int main()
{
    std::string cnum="";
    std::vector<std::vector<long long>> mainVec;
    int pos=0;
    while (true)
    {
        std::vector<long long> cvec;
        while (true) {
             //std::cin wont get spaces
            char c=getchar(); 
            //we reached the space so lets parse it and go to next num
            if (c == ';') {
                int num;
                try
                {
                    //will throw if can't parse so inside of try cache
                    num=std::atoll(cnum.c_str());
                    cvec.push_back(num);
                }
                catch (const std::exception&)
                {
                    std::cout << "can't parse the number";
                }
              //make ready for next num
                cnum.clear();
            }
            else if (c == ' ') {
               
                int num;
                try
                {                   //will throw if can't parse so inside of try cache
                    num=std::atoll(cnum.c_str());
                    cvec.push_back(num);
                }
                catch (const std::exception&) {
                    std::cout << "can't parse the number";
                }
                //go to next vector
                mainVec.push_back(cvec);
                cvec.clear();
                //or use std::move
                break;
            }
            //end this operation
            else if (c == 'e') {
                int num;
                try
                {                   //will throw if can't parse so inside of try cache
                   num= std::atoll(cnum.c_str());
                    cvec.push_back(num);
                }
                catch (const std::exception&) {
                    std::cout << "can't parse the number";
                }
                //add last vector and break the loops
                mainVec.push_back(cvec);
                goto rest;
            }
            else
                cnum += c;
        }
    }
rest:
    std::cout << "the end";

}

you can do the optimizations yourself (reducing rapeated code in each if case)

What you need is a way to look ahead in the input. If you know whether the next character is a space, a semi-colon, a digit or a minus sign then you can make the correct decision on what to read.

Here's function that does this for you

int peek_char(istream& input)
{
    int ch = input.get();
    if (ch >= 0)
        input.put_back(ch);
    return ch;
}

With this function you know what the next character is going to be without reading it . If there is no next character (because of end of file) it will return a negative number.

You could use istream::peek :

auto read_sets(std::istream& is) {
    std::vector<std::vector<double>> sets;
    std::vector<double> current_vector;

    double number;
    while (is >> number)
    {
        current_vector.push_back(number);
        switch (is.peek())
        {
            case ';': // ignore semicolons
                is.ignore(1);
                break;

            case ' ': // move to the next set
                sets.push_back(std::move(current_vector));
                current_vector.clear();
                break;

            default: // no need to handle dots and digits. EOF is handled in while condition
                break;
        }
    }
    
    sets.push_back(std::move(current_vector)); // push the last set
    return sets;
}

Ok so i tried all the suggestions that were posted here, and i couldn't really make it work for my problem, mostly because these suggestions used advanced stuff that i haven't learn. For the getline suggestion it was almost working but i couldn't make it work perfectly. So, i remembered that i did a similar kind of reading before and i tried to use that idea and it worked very good. I don't think that it's the best idea but it's a trick that works and i wanted to post it here if anyone will have the same problem as me. The detail that i forgot to mention is that i know the dimension of the vector can be 2, 3 or 4, (because i need to treat that vector as a point in 2,3 or 4 dimension in my problem) so i can use scanf for that, like this:

double a,b,c,d;
std::vector<Point *> points;
int x = scanf("%lf;%lf;%lf;%lf ",&a,&b,&c,&d);
while(x != EOF){
    if(x == 2){
        points.emplace_back(new Point2D(a,b));
    }
    if(x == 3){
        points.emplace_back(new Point3D(a,b,c));
    }
    if(x==4){
        points.emplace_back(new Point4D(a,b,c,d));
    }
    x = scanf("%lf;%lf;%lf;%lf ", &a,&b,&c,&d);
    if(x == 0) break;   //i don't think this is necesary , but without it my debugger wouldn't work

The idea of the problem is that i have a class Point that i extended in 3 more classes, Poin2D, Point3D, Point4D. Point2D has 2 coordinates, Point3D has 3 coordinates and Point4D has 4 coordinates and each object has a constructor with the coordinates as parameters

Thanks everyone for trying to help me! :)

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