Pregunta

I'm a C++ newbie who came from Java, so I need some guidance on some really basic issues I'm stumbling upon as I go.

I'm reading lines from a file, and each line consists of 6 strings/ints, which will be sent as parameters to a temporary variable.

Example:

Local1,Local2,ABC,200,300,asphalt

However, there are two subtypes of variable. One has a string as the last parameter (like 'asphalt' in the example above). The other one has an int instead. I have a method that reads each parameter and sends it to a variable, but how do I detect if the last bit of string is an integer or a string beforehand, so I know if I should send it to a Type1 variable or a Type2 one?

Many thanks!

¿Fue útil?

Solución

Since you want to determine the type of the last column, then this ought to work:

#include <iostream>
#include <string>
#include <cstdlib>
#include <vector>
#include <sstream>
#include <cctype>
#include <algorithm>

enum Types {
    NONE,
    STRING,
    INTEGER,
    DOUBLE
};

struct Found {
    std::string string_val;
    int integer_val;
    double double_val;
    enum Types type;
};

//copied verbatim from:
//http://stackoverflow.com/a/2845275/866930
inline bool isInteger(const std::string &s) {
   if(s.empty() || ((!std::isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) return false;

   char * p ;
   std::strtol(s.c_str(), &p, 10);

   return (*p == 0);
}

//modified slightly for decimals:
inline bool isDouble(const std::string &s) {
   if(s.empty() || ((!std::isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) return false ;

   char * p ;
   std::strtod(s.c_str(), &p) ;

   return (*p == 0);
}

bool isNotAlpha(char c) {
    return !(std::isalpha(c));
}

//note: this searches for strings containing only characters from the alphabet
//however, you can modify that behavior yourself.
bool isString (const std::string &s) {
    std::string::const_iterator it = std::find_if(s.begin(), s.end(), isNotAlpha);
    return (it == s.end()) ? true : false;
}

void determine_last_column (const std::string& str, Found& found) {
    //reset found:
    found.integer_val = 0;
    found.double_val = 0;
    found.string_val = "";
    found.type = NONE;

    std::string temp;
    std::istringstream iss(str);

    int column = 0;
    char *p;

    while(std::getline(iss, temp, ',')) {
        if (column == 5) {
            //now check to see if the column is an integer or not:
            if (isInteger(temp)) {
                found.integer_val = static_cast<int>(std::strtol(temp.c_str(), &p, 10));
                found.type = INTEGER;
            }
            else if (isDouble(temp)) {
                found.double_val = static_cast<double>(std::strtod(temp.c_str(), &p));
                found.type = DOUBLE;
            }
            else if (isString(temp)) {
                found.string_val = temp;
                found.type = STRING;
            }
        }
        ++column;
    }

    if (found.type == INTEGER) {
        std::cout << "An integer was found: " << found.integer_val << std::endl;
    }
    else if(found.type == DOUBLE) {
        std::cout << "A double was found: " << found.double_val << std::endl;
    }
    else if(found.type == STRING) {
        std::cout << "A string was found: " << found.string_val << std::endl;
    }
    else {
        std::cout << "A valid type was not found! Something went wrong..." << std::endl;
    }
}

int main() {
    std::string line_t1 = "Local1,Local2,ABC,200,300,asphalt";
    std::string line_t2 = "Local1,Local2,ABC,200,300,-7000.3";

    Found found;

    determine_last_column(line_t1, found);
    determine_last_column(line_t2, found);

    return 0;
}

This outputs and correctly assigns the appropriate value:

A string was found: asphalt
An integer was found: -7000.3

This version works on int, double, string; does not require boost; and, is plain vanilla C++98.

REFERENCES:

UPDATE:

This version now supports both positive and negative numbers that are integers or doubles, in addition to strings.

Otros consejos

First, create an array that can store both strings and integers:

std::vector<boost::variant<std::string, int>> items;

Second, split the input string on commas:

std::vector<std::string> strings;
boost::split(strings, input, boost::is_any_of(","));

Last, parse each token and insert it into the array:

for (auto&& string : strings) {
    try {
        items.push_back(boost::lexical_cast<int>(string));
    } catch(boost::bad_lexical_cast const&) {
        items.push_back(std::move(string));
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top