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

时间:2017-02-13 15:38:36

标签: c++ stringstream c++98

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

作为类赋值的一部分,我的任务是将空格分隔的字符串转换为浮点数(然后用这些浮点数计算一个范围,但这与我的问题无关)。字符串来自文本文件。如果浮点数有任何差异,我应该忽略它并认为它已损坏。例如,文本文件可能包含如下所示的行:

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并尝试忽略剩余的字符,直到下一个空格分隔符出现。但是,文本文件的行如下:

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

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

处理这个istringstream问题的正确方法是什么,其中字符不会被我想要的方式忽略?

我的教授告诉我,我可以通过非常基本的STL技术来实现这一目标。他明确建议使用stringstream作为解析浮点数的方法。他在这里错了吗?

如有需要,请发表评论以进一步明确;我现在已经有很长一段时间了,非常感谢你的帮助。

谢谢!

2 个答案:

答案 0 :(得分:1)

尝试以下方法,如演示程序中所示。

#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 == '\0' && -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;
}

输出与上面显示的相同。

答案 1 :(得分:1)

这应该做你需要的。

#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的输入会返回以下输出:

34.6
24.2
18.a failed!
54.3
20
15.6

编辑:我在if语句中添加了一个案例来处理陌生人案例(即13-6)。这是我找到的一个简洁的解决方案here

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