免责声明:我必须使用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
作为解析浮点数的方法。他在这里错了吗?
如有需要,请发表评论以进一步明确;我现在已经有很长一段时间了,非常感谢你的帮助。
谢谢!
答案 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:我注释了一些更复杂的部分。