I have two cases of input for which I want to use the same method. The first case is that the given parameter is a std::string containing three digits that I need to convert into int:
std::string pointLine = "1 1 1";
The second case is that the given parameter is a std::string containing three "not yet doubles" that I need to convert into doubles:
std::string pointLine = "1.23 23.456 3.4567"
I have written the following method:
std::vector<double> getVertexIndices(std::string pointLine) {
vector<int> vertVec;
vertVec.push_back((int) pointLine.at(0));
vertVec.push_back((int) pointLine.at(2));
vertVec.push_back((int) pointLine.at(4));
return vertVec;
}
This works fine for the first case, but not for having a line that is supposed to be converted to doubles.
So I tried the solution Double split in C . I get that my delimiter would be " ".
This is what I came up with as for now, but the program crashes after first call of the following method:
std::vector<double> getVertexIndices(std::string pointLine) {
vector<double> vertVec;
char * result = std::strtok(const_cast<char*>(pointLine.c_str()), " ");
while(result != NULL ) {
double vert = atof (result);
vertVec.push_back(vert);
char * result = std::strtok(NULL, " ");
}
return vertVec;
}
Method 1: Using paste() paste() function is used to combine strings present in vectors passed to it an argument. Parameter: vectors are the input vectors to be concatenate. sep is the separator symbol that separates the strings present in the vector.
Instead of copying, you can directly initialize your vector from iterators.
// include <string>, <vector>, <iterator> and <sstream> headers
std::vector<double> getVertexIndices(std::string const& pointLine)
{
std::istringstream iss(pointLine);
return std::vector<double>{
std::istream_iterator<double>(iss),
std::istream_iterator<double>()
};
}
This works exactly the same way for your ints. Your int-approach will not do what you intended for strings like "123 456 789"
The main problem with your attempt is that strtok()
will modify the pointer passed as input. Doing so with a pointer obtained via std::string::c_str()
will wreak havoc inside the string object.
All other answers provided here were pretty good. From what you've stated, you only need to read 3 doubles (an x,y,z vertex), so you could optimize the function to use some other fixed-size container that doesn't allocate memory (std::vector
will allocate). In the following example, I've used an std::tuple
to return the results. I've also used std::stod()
which is a C++11 function that parses a double from a string. It will throw an exception if conversion fails, which might also be useful for your application.
#include <iostream> // std::cout
#include <string> // std::stod
#include <tuple> // std::tuple
std::tuple<double, double, double> getVertexIndices(const std::string & pointLine)
{
size_t xEnd, yEnd;
const double x = std::stod(pointLine, &xEnd);
const double y = std::stod(pointLine.substr(xEnd), &yEnd);
const double z = std::stod(pointLine.substr(xEnd + yEnd));
return std::make_tuple(x, y, z);
}
// Test case:
int main()
{
const std::string pointLine1 = "1 2 3";
const std::string pointLine2 = "1.23 23.456 3.4567";
std::tuple<double, double, double> v1 = getVertexIndices(pointLine1);
std::cout << "x = " << std::get<0>(v1) << std::endl;
std::cout << "y = " << std::get<1>(v1) << std::endl;
std::cout << "z = " << std::get<2>(v1) << std::endl;
std::tuple<double, double, double> v2 = getVertexIndices(pointLine2);
std::cout << "x = " << std::get<0>(v2) << std::endl;
std::cout << "y = " << std::get<1>(v2) << std::endl;
std::cout << "z = " << std::get<2>(v2) << std::endl;
return (0);
}
Use std::istringstream
:
std::vector<double> getVertexIndices(std::string pointLine)
{
vector<double> vertVec;
std::istringstream s(pointLine);
double d;
while (s >> d) {
vertVec.push_back(d);
}
return vertVec;
}
It's quite simple, really. You construct a stream which will read from the string. Then just use normal stream extraction to fill the vector.
Of course, you can leverage the standard library iterator adaptors and similar, to produce something like this:
std::vector<double> getVertexIndices(std::string pointLine)
{
std::vector<double> vec;
std::istringstream s(pointLine);
std::copy(
std::istream_iterator<double>(s) // start
, std::istream_iterator<double>() // end
, std::back_inserter(vec) // destination
);
return vec;
}
As a side note (thanks to @ikh), you might want to change the function to take a const std::string &
- there's no need to take the string by value.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With