从C++文件中读取不同类型的数字数据
Reading numeric data of different types from a file in C++
我有一个文件,前几行看起来像这样:
1 436.514 0.587 8.318 1 3 8 0.929 7 0.972 2 1.440
2 436.004 0.744 7.020 1 3 10 1.117 9 1.155 1 1.440
3 436.263 0.603 5.029 2 1 9 0.916
4 437.966 0.594 6.086 2 1 9 0.835
5 434.577 1.454 5.820 2 1 10 0.898
6 433.990 1.139 7.596 2 1 10 0.919
7 437.917 0.102 8.485 4 3 1 0.972 11 1.503 12 1.428
8 435.617 0.849 9.510 4 3 13 1.463 1 0.929 14 1.490
9 436.839 0.691 5.880 4 3 4 0.835 3 0.916 2 1.155
10 434.623 1.036 6.798 4 3 6 0.919 5 0.898 2 1.117
11 438.321 39.569 9.683 3 1 7 1.503
12 438.614 39.463 7.420 3 1 7 1.428
13 434.384 1.154 9.304 3 1 8 1.463
问题是我无法转换这些值,这些值在称为 line 的变量中读取为字符串,然后存储到由空格分隔的单独字符数组中。但我的问题是我无法使用 std C++函数将这些值转换为适当的类型。
我的意思是我不控制文件中不同位置的值,因此我无法提供预定义的函数将其转换为该类型。
例如:在第一行中,第一个值是 int,后跟 3 个浮点数,然后是 int,依此类推。而且,每行中的值数量也不是恒定的。因此,我无法将它们转换为所需的类型。我已经尝试了lexical_cast
,如果值与预定义的类型不同,则无法转换值。
例如:如果我有 让我们说
str = "123";
float num = lexical_cast<float>(str)
它给了我一个错误。对于只能转换具有该类型值的字符串的stof
或stod
函数也是如此。
这是我现在的代码:
while (i < line.length()){
if (line[i] != ' '){
a[j++] = line[i++];
if (i == line.length()){
a[j] = ' ';
------->int num = std::stoi(a);
std::cout << num << " ";
}
}
else{
a[j] = ' '; j = 0;
----------->float num = std::stof(a);
std::cout << num << " ";
while (line[i] == ' ') i++;
}
}
用箭头标记的位置是问题区域。我能否以任何方式轻松地将这些值读取到适当类型的适当变量中。
注意:我无法在考虑其类型的情况下手动插入每个变量,因为行数为 100000。所以这是不可能的。
我想这对你来说太过分了。
仍然想向公众展示,如果您使用知道如何投影到 AST 数据类型的分析器生成器,代码会变得多么优雅。下面是一个 Spirit 示例,它会自动处理所有转换为line_rec
所在的vector<line_rec>
:
struct line_record {
int a;
float b, c, d;
int e;
// column f is rest.size()
std::vector<std::pair<int, float> > rest;
};
法典
住在科里鲁
#include <boost/fusion/include/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
struct line_record {
int a;
float b, c, d;
int e;
// column f is rest.size()
std::vector<std::pair<int, float> > rest;
};
BOOST_FUSION_ADAPT_STRUCT(line_record, a, b, c, d, e/*, f*/, rest)
// define a Spirit Grammar
using Iterator = boost::spirit::istream_iterator;
namespace parser {
static auto const line = [] {
using namespace boost::spirit::qi;
_a_type number_of_pairs;
rule<Iterator, line_record(), locals<unsigned> > line_parser;
return line_parser %= skip(blank) [
int_ >> float_ >> float_ >> float_ >>
int_ >> omit[ uint_ [ number_of_pairs = _1 ] ] >>
repeat(number_of_pairs) [ int_ >> float_ ] >>
(eol|eoi)
];
}();
}
#include <fstream>
int main() {
using namespace std;
ifstream ifs("input.txt");
Iterator first(ifs >> noskipws), last;
vector<line_record> all_data;
if (parse(first, last, *parser::line, all_data))
{
cout << "Parsed " << all_data.size() << " linesn";
for (auto& rec : all_data) {
cout << rec.a << "t"
<< rec.b << "t" << rec.c << "t" << rec.d << "t"
<< rec.e << "t"
<< rec.rest.size();
for (auto& trailing : rec.rest)
cout << "t(" << trailing.first << ", " << trailing.second << ")";
cout << "n";
}
} else {
cout << "Parse failedn";
}
if (first != last) {
cout << "Remaining input: '" << string(first, last) << "'n";
}
}
输出
鉴于您的问题输入:
Parsed 13 lines
1 436.514 0.587 8.318 1 3 (8, 0.929) (7, 0.972) (2, 1.44)
2 436.004 0.744 7.02 1 3 (10, 1.117) (9, 1.155) (1, 1.44)
3 436.263 0.603 5.029 2 1 (9, 0.916)
4 437.966 0.594 6.086 2 1 (9, 0.835)
5 434.577 1.454 5.82 2 1 (10, 0.898)
6 433.99 1.139 7.596 2 1 (10, 0.919)
7 437.917 0.102 8.485 4 3 (1, 0.972) (11, 1.503) (12, 1.428)
8 435.617 0.849 9.51 4 3 (13, 1.463) (1, 0.929) (14, 1.49)
9 436.839 0.691 5.88 4 3 (4, 0.835) (3, 0.916) (2, 1.155)
10 434.623 1.036 6.798 4 3 (6, 0.919) (5, 0.898) (2, 1.117)
11 438.321 39.569 9.683 3 1 (7, 1.503)
12 438.614 39.463 7.42 3 1 (7, 1.428)
13 434.384 1.154 9.304 3 1 (8, 1.463)
我只有几分钟的时间,但这里有一个合适的代码的大纲,它假设你想同时将所有数据保存在内存中以进行一些跨行分析:
struct Data
{
int a;
float b, c, d;
int e, f;
std::vector<std::pair<int, float>> g;
};
int main()
{
int line_num = 0;
std::vector<Data> all_data;
if (std::ifstream in(filename))
{
std::string line;
while (getline(in, line))
{
++line_num;
std::istringstream iss(line);
Data data;
if (iss >> data.a >> data.b >> data.c >> data.d
>> data.e >> data.f)
{
int i; float f;
while (iss >> i >> f)
data.g.push_back(std::make_pair(i, f));
all_data.push_back(data);
}
else
std::cerr << "unable to parse mandatory fields "
"from line #" << line_num << " '" << line
<< "', ignoring and continuing...n";
}
... use all_data for whatever analysis you want...
}
else
std::cerr << "unable to open filen";
}
笔记
- 逐行读取,然后使用
istringstream
解析值 - 使用额外的循环来读取 - 行尾出现多对
int
/float
值
您可以尝试使用 ifstream.getline() 和 sscanf 的组合来处理该文件,它告诉它在字符串中找到了多少匹配项。
#include <iostream>
#include <fstream>
#include <cstdio>
int main(void)
{
double a, b, c, d, e, f;
int i, j, k, l, m, n;
char buffer[160];
std::ifstream file;
file.open("data.txt");
while (!file.eof()) {
// check if this fails
file.getline(buffer, 160);
if (file.eof()) break;
a = b = c = d = e = f = 0.0;
i = j = k = l = m = n = 0;
int res = sscanf(buffer,
"%d %lf %lf %lf %d %d %d %lf %d %lf %d %lf",
&i, &a, &b, &c, &j, &k, &l, &d, &m, &e, &n, &f);
std::cout << "Got " << res << " fields" << std::endl;
}
}`
相关文章:
- 我收到同义重复编译器错误。我应该如何修复"类型"X"的参数与类型"X"的参数不兼容?
- 当我输入字符类型的数字时,为什么我无法获得整数?
- 正则表达式以匹配数字的重复模式,后跟任何类型的分隔符?
- 你能在 c++ 中将不同的数字类型加在一起吗?
- 输出一个数字,该数字可能是三种类型之一
- 如何用不同的参数类型和数字回调函数
- C/C++ - 用于按顺序打印数字的 sem_t 类型的单个信号量
- typeid.name 返回派生类类型之前的数字
- C++小数点后有 200 位数字的类型?
- 为什么我不能在同一行中定义两个相同类型的类的成员指针
- 常量整数变量和数字的不同类型推导
- 检测<T>某些非数字类型 T 的 std::numeric::type 的特化
- 随机数字双重类型
- CRTP 模式 但是在数据结构中存储非同构类型
- 当数字可能超出C++中特定数据类型的范围时如何处理异常?
- 为什么数字类型只有"to_string()"?
- 如何在数字大于类型 size_t 的最大数量时使用 std::bitset
- C++从文件中读取不同类型的数据,直到有一个以数字开头的字符串
- 无符号窄字符类型数字表示
- c++中对包含双精度类型数字的数组进行排序的最快方法是什么?