我想在C ++中读取一个输入文件,其结构(或缺少)类似于 text = number 的一系列行,例如
input1 = 10
input2 = 4
set1 = 1.2
set2 = 1.e3
我想把这个号码拿出来,把剩下的号码扔掉。数字可以是整数或双数,但我知道它们是一个还是其他。
我也想阅读它,例如
input1 = 10
input2=4
set1 =1.2
set2= 1.e3
以便对用户更加健壮。我认为这意味着它不应该是格式化的红色。
无论如何,有没有明智的方法呢?
我已经尝试了以下内容,但对我一直在做的事情知之甚少,结果如预期的那样......没有成功。
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <math.h>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
#include <boost/lexical_cast.hpp>
#include <string>
using namespace std;
using namespace boost;
int main(){
string tmp;
char temp[100];
int i,j,k;
ifstream InFile("input.dat");
//strtol
InFile.getline(temp,100);
k=strtol(temp,0,10);
cout << k << endl;
//lexical_cast
InFile.getline(temp,100);
j = lexical_cast<int>(temp);
cout << j << endl;
//Direct read
InFile >> tmp >> i;
cout << i << endl;
return 0;
}
答案 0 :(得分:6)
一次只读一行 然后在'='符号上分割每一行。使用流功能完成剩下的工作。
#include <sstream>
#include <fstream>
#include <iostream>
#include <string>
int main()
{
std::ifstream data("input.dat");
std::string line;
while(std::getline(data,line))
{
std::stringstream str(line);
std::string text;
std::getline(str,text,'=');
double value;
str >> value;
}
}
进行错误检查:
#include <sstream>
#include <fstream>
#include <iostream>
#include <string>
int main()
{
std::ifstream data("input.dat");
std::string line;
while(std::getline(data,line))
{
std::stringstream str(line);
std::string text;
double value;
if ((std::getline(str,text,'=')) && (str >> value))
{
// Happy Days..
// Do processing.
continue; // To start next iteration of loop.
}
// If we get here. An error occurred.
// By doing nothing the line will be ignored.
// Maybe just log an error.
}
}
答案 1 :(得分:5)
这里已经有一些很好的解决方案了。然而,只是为了抛弃它,一些评论意味着Boost Spirit对于这个问题是不恰当的解决方案。我不确定我是否完全不同意。但是,以下解决方案非常简洁,可读(如果您知道EBNF)并且容错。我考虑使用它。
#include <fstream>
#include <string>
#include <boost/spirit.hpp>
using namespace std;
using namespace boost::spirit;
int main()
{
ifstream data("input.dat");
string line;
vector<double> numbers;
while(getline(data,line))
{
parse(line.c_str(),
*(+~ch_p('=') >> ch_p('=') >> real_p[push_back_a(numbers)]),
space_p);
}
}
答案 2 :(得分:2)
C FTW(经过修改以处理双打)
#include <stdio.h>
int
main ()
{
double num;
while (!feof (stdin))
if (1 == fscanf (stdin, "%*[^=] = %lf", &num))
printf ("%g\n", num);
return 0;
}
答案 3 :(得分:2)
我是否做对了:你拿线,从中提取数字并将其打印出来(或者在其他地方使用它,无论如何)?如果是这样,你可以使用字符串函数和istringstream:
//these are your codes, removing some though
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <math.h>
#include <iostream>
#include <fstream>
#include <string>
//adding
#include <sstream>
using namespace std;
int main()
{
string line="", extract="";
int placeofop=0, input;
ifstream InFile("input.dat");
while(!InFile.eof())
{
getline(InFile, line);
placeofop = line.find("=");
extract = line.substr(placeofop, (line.length()-placeofop));
istringstream trythis(extract);
trythis >> input;
cout << input << endl;
}
return 0;
}
我不是百分百确定我是否记得正确的功能,但是如果我把它们全部正确的话,这应该有用。
编辑:我意识到我可以编辑我的帖子:)我在评论中反转了&lt;&lt;&lt;&lt;&lt;&lt;&gt;&gt;&gt;我一直在做的事情......现在没有编译错误。
答案 4 :(得分:2)
脱离我的头顶:
vector<double> vals(istream &in) {
vector<double> r;
string line;
while (getline(f, line)) {
const size_t eq = line.find('=');
if (eq != string::npos) {
istringstream ss(line.substr(eq + 1));
double d = 0;
ss >> d;
if (ss) r.push_back(d);
else throw "Line contains no value";
}
else {
throw "Line contains no =";
}
}
return r;
}
int main(int argc, char *argv[]) {
vector<double> vs = vals(ifstream(argv[1]));
}
答案 5 :(得分:1)
现在您已经在lexical_cast中使用了boost,只需将boost::split()和boost::is_any_of()的每一行解析为1个2元素向量,并启用token_compress。
以下代码说明了解析,但跳过了数字转换,可以使用boost lexical_cast轻松解决。
#include <fstream>
#include <sstream>
#include <string>
#include <iostream>
#include <vector>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/foreach.hpp>
using std::string;
using std::cout;
using std::ifstream;
using std::stringstream;
using std::vector;
std::string file_to_string()
{
ifstream data("data.txt");
stringstream s;
s << data.rdbuf();
return s.str();
}
void print_parameter(vector<string>& v)
{
cout << v_para[0];
cout << "=";
cout << v_para[1];
cout << std::endl;
}
vector<string> string_to_lines(const string& s)
{
return v_lines;
}
int main()
{
vector<string> v_lines;
boost::split(v_lines, file_to_string(), boost::is_any_of("\n"), boost::token_compress_on);
vector<string> v_para;
BOOST_FOREACH(string& line, v_lines)
{
if(line.empty()) continue;
boost::split(v_para, line, boost::is_any_of(" ="), boost::token_compress_on);
// test it
print_parameter(v_para);
}
}
答案 6 :(得分:1)
如果您正在设计此格式,我建议采用INI file格式。 轻量级语法INI格式包括部分(允许您在格式中具有更多结构),在您的情况下可能需要或可能不需要:
即
[section_1]
variable_1=value1
variable_2=999
[sectionA]
variable_A=value A
variable_B=111
此维基百科页面上的外部链接列出了许多库,这些库可用于处理这些类型的文件,这些文件从Windows API扩展/替换基本的GetPrivateProfileString函数并支持其他平台。 其中大多数会处理空间填充=符号(或至少在=之前,因为=之后的空格可能是有意/重要的。 如果您不希望这些库中的某些库也可能有省略[sections]的选项(我自己的C ++类用于处理类似于格式文件的INI具有此选项)。
这些库和/或使用Windows API GetPrivateProfileXXX函数的优点是您的程序可以访问特定变量 (即,在没有程序必须的情况下,从sectionA获取或设置variable_A的值) 写/扫描/重写整个文件。
答案 7 :(得分:0)
这是我最快捷的STL解决方案:
#include <fstream>
#include <list>
#include <locale>
void foo()
{
std::fstream f("c:\\temp\\foo.txt", std::ios_base::in);
std::list<double> numbers;
while (!f.eof())
{
int c = f.get();
if (std::isdigit(c, std::locale::classic()) ||
c == '+' ||
c == '-' ||
c == '.')
{
f.putback(c);
double val;
f >> val;
if (f.fail()) {
f.clear(f.eof() ? std::ios_base::eofbit : std::ios_base::goodbit);
continue;
}
else
{
numbers.push_back(val);
}
}
}
}
答案 8 :(得分:0)
刚测试过这个......它可以工作,并且不需要C ++标准库以外的任何东西。
#include <iostream>
#include <map>
#include <string>
#include <algorithm>
#include <iterator>
#include <cctype>
#include <sstream>
using namespace std; // just because this is an example...
static void print(const pair<string, double> &p)
{
cout << p.first << " = " << p.second << "\n";
}
static double to_double(const string &s)
{
double value = 0;
istringstream is(s);
is >> value;
return value;
}
static string trim(const string &s)
{
size_t b = 0;
size_t e = s.size();
while (b < e && isspace(s[b])) ++b;
while (e > b && isspace(s[e-1])) --e;
return s.substr(b, e - b);
}
static void readINI(istream &is, map<string, double> &values)
{
string key;
string value;
while (getline(is, key, '='))
{
getline(is, value, '\n');
values.insert(make_pair(trim(key), to_double(value)));
}
}
int main()
{
map<string, double> values;
readINI(cin, values);
for_each(values.begin(), values.end(), print);
return 0;
}
编辑:我刚刚阅读了原始问题,并注意到我没有提出确切的答案。如果您不关心密钥名称,juts会丢弃它们。另外,为什么需要确定整数值和浮点值之间的差异? 1000
是整数还是浮点数?那么1e3
还是1000.0
呢?检查给定的浮点值是否为整数是很容易的,但是有一个数字的clas既是有效整数又是有效的浮点值,如果你想处理,你需要进入自己的解析例程这是正确的。