如何将包含双精度浮点数的std::string转换为双精度浮点数向量?

6

我有两个输入情况,想要使用同一个方法来处理。 第一个情况是给定的参数是一个包含三位数字的std::string,我需要将其转换为int类型:

std::string pointLine = "1 1 1";

第二种情况是给定的参数是一个std::string,其中包含三个“尚未转换为double”的值,我需要将它们转换为double。
std::string pointLine = "1.23 23.456 3.4567"

我写了以下方法:

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;

对于第一种情况,这样做很好,但是把一行转换成双精度浮点数时就不行了。

所以我尝试了 C语言中的双精度浮点数分割 的解决方案。我知道我的分隔符是空格。

目前我想到的代码如下,但是在调用以下方法后程序会崩溃:

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;

}

3个回答

11

你可以直接从迭代器初始化你的向量,而不是复制。

// 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>()
  };
}

对于整数,这个方法完全相同。你的整数方法对于像"123 456 789"这样的字符串将不会产生你预期的结果。


谢谢!这对我想要的完美运作。感谢您提到超过一位数字的整数的备注。我刚遇到了这个问题。 - Reatus

8
使用 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;
}

实际上很简单,您可以构建一个从字符串中读取的流,然后使用正常的流提取来填充向量。

当然,您还可以利用标准库迭代器适配器等工具,编写类似以下代码:

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;
}

作为一个附注(感谢@ikh),你可能想要将函数更改为采用const std :: string& - 没有必要按值传递字符串。

感谢您提供的解决方案。我通常喜欢提前初始化所有内容。这确实有所帮助,但我选择了另一种方法,因为我认为它更简洁,而且不需要编写循环,这让我认为在性能方面更好。备注:性能方面的想法只是一种感觉,并没有知识支持。 - Reatus

2
你的尝试的主要问题是strtok()将修改作为输入传递的指针。如果使用通过std::string::c_str()获得的指针进行这样的操作,将会在字符串对象内部造成严重破坏。
这里提供的所有其他答案都非常好。根据你所述,你只需要读取3个双精度浮点数(一个x、y、z顶点),因此你可以优化该函数以使用一些不分配内存的固定大小容器(std::vector将分配内存)。在下面的示例中,我使用了一个std::tuple来返回结果。我还使用了std::stod(),这是一个C++11函数,用于从字符串解析双精度浮点数。如果转换失败,它将抛出异常,这对于你的应用程序也可能很有用。
#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);
}

谢谢您的解释!我找到了另一个更好的解决方案,但是您的评论帮助我更清楚地理解了事情! - Reatus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接