将字符串转换为浮点数;无法正确清除 stringstream?

Converting string to floats; can't clear stringstream correctly?

免责声明:我必须使用 c++ 98

作为 class 作业的一部分,我的任务是将 space 分隔的字符串转换为浮点数(然后用这些浮点数计算跨度,但这与我的问题无关)。字符串来自文本文件。如果浮动有任何差异,我应该忽略它并认为它已损坏。例如,一个文本文件可能包含这样一行:

34.6 24.2 18.a 54.3 20.0 15.6

在这种情况下,18.a 将被简单地视为已损坏,无需对其进行进一步操作。

现在,我在清除损坏数据的字符串流时遇到了问题。作为参考,这是我的代码:

#include <vector>
#include <limits>
#include <string>
#include <sstream>
#include <fstream>
#include <iostream>
using namespace std;

int main(int argc, char* argv[]) {

    //Open file
    ifstream infile("dataFile");

    //Get all file input into a single string
    string line;
    string buffer;
    while (getline(infile, buffer)) {
        line += buffer + " ";
    }

    infile.close();

    //Populate vector
    float temp;

    //I have tried to clear the stream with `data >> dummy` for
    //both string and single char types below, but `data >> string`
    //always clears too much, and `data >> char` doesn't seem to clear
    //correctly either

    //string dummy;
    //char dummy;
    vector<float> temps;
    istringstream data(line);
    while (data) {
        //values between -100 and 100 are also considered corrupt
        if (data >> temp && (temp <= 100 && temp >= -100)) {
            temps.push_back(temp);
        }
        else if (!data.eof()) {
            data.clear();

            //trying to ignore all characters until I reach a space
            //but that doesn't work correctly either

            data.ignore(numeric_limits<streamsize>::max(), ' ');
            //data >> dummy;
            //cout << "Dummy: " << dummy << endl;
            temps.push_back(-101.0);
        }
    }

    //display resulting vector values
    for(int i=0; i<temps.size(); ++i) {
        cout << temps[i] << " ";
    }
    cout << endl;
}

我的问题出在 while (data) 循环内,特别是在 else if (!data.eof()) 块内。当 data >> temp (type float) 失败时,else if 块运行。我清除了相应的 failbit 并尝试忽略剩余的字符,直到出现下一个 space 分隔符。但是,文本文件中有这样一行:

a *a -100.1 100.1 a 10.a a 13-6s 12abc -12.a

产生问题。 13 和 -6 都被处理为有效的浮点数。我想忽略 13-6s 的整个块,因为这些值旨在以 space 分隔。

处理这个 istringstream 问题的正确方法是什么,字符没有按照我想要的方式被忽略?

我的教授告诉我,我可以使用非常基本的 STL 技术来完成此任务。他明确建议使用 stringstream 作为解析浮点数的方法。他错了吗?

如果需要,请评论以进一步说明;我从事此工作已经有一段时间了,非常感谢您的帮助。

谢谢!

尝试使用演示程序中显示的以下方法。

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

int main() 
{
    std::string line( "a *a -100.1 100.1 -100 a 10.a a 13-6s 100 12abc -12.a" );
    std::istringstream is( line );

    std::vector<float> values;
    std::string item;

    while ( is >> item )
    {
        const char *s = item.c_str();
        char *tail;

        float value = std::strtof( s, &tail );

        if ( *tail == '[=10=]' && -100.0f <= value && value <= 100.0f ) 
        {
            values.push_back( value );
        }           
    }


    for ( float value : values ) std::cout << value << ' ';
    std::cout << std::endl;

    return 0;
}

程序输出为

-100 100 

如果使用这个字符串

std::string line( "34.6 24.2 18.a 54.3 20.0 15.6" );

那么程序输出将是

34.6 24.2 54.3 20 15.6

另一种方法如下。

#include <iostream>
#include <string>
#include <sstream>
#include <limits>
#include <vector>

int main() 
{
    std::string line( "a *a -100.1 100.1 -100 a 10.a a 13-6s 100 12abc -12.a" );
//  std::string line( "34.6 24.2 18.a 54.3 20.0 15.6" );
    std::istringstream is( line );

    std::vector<float> values;

    while ( !is.eof() )
    {
        float value;
        int c;

        if ( not ( is >> value ) || ( ( c = is.get() ) != ' ' && c != std::char_traits<char>::eof() ) )
        {
            is.clear();
            is.ignore( std::numeric_limits<std::streamsize>::max(), ' ' );
        }
        else if ( -100.0f <= value && value <= 100.0f ) 
        {
            values.push_back( value );
        }           
    }

    for ( float value : values ) std::cout << value << ' ';
    std::cout << std::endl;

    return 0;
}

输出与上图相同。

这应该可以满足您的需求。

#include <iostream>
#include <string>
#include <sstream>

int main() {
  std::string temp;

  // cin will write to temp with each space delimited entry
  while (std::cin >> temp) {
    std::stringstream s(temp);
    float f;

    // the first case checks if the actual write the float succeeds
    // the second case checks if the entire stringstream has been read
    if (!(s >> f) || !s.eof()) {
      std::cout << temp << " failed!" << std::endl;
    }
    else {
      std::cout << f << std::endl;
    }
  }
}

很抱歉无法回答您的 stringstream 问题,但此解决方案应该消除了任何必要性。

请注意,34.6 24.2 18.a 54.3 20.0 15.6 returns 的输入是:

的输出
34.6
24.2
18.a failed!
54.3
20
15.6

编辑:我在 if 语句中添加了一个案例来处理陌生案例(即 13-6s)。这是我发现的一个巧妙的解决方案 here.

编辑 2:我注释了一些更复杂的部分。