我有一个文本文件,其中包含一些我需要解析并放入适当数组结构的信息(我猜这些是C ++中的向量)。
我试图解析的文本文件包含我想忽略的双精度,整数和空格。
我有使用Python的经验,使用Python可以使用split()方法。
在C ++中,我可以使用boost tokenizer或许多其他工具集。我已经尝试了很多这些方法,但在我最好的尝试中,我最终得到一个像这样的数字“-97.653632.431542”,我甚至不知道C ++如何允许两个小数点。 (我知道问题是我缺乏经验,而不是C ++!)
所以现在就好了。首先让我们定义文本文件的内容,其中包含可变数量的空格,所以我会先插入几行代码,开头包含X个空格,(我知道我可以使用{{1但是,为了示例完整性,我想在这里包含它们)。
注意:我可以使用我想要的任何库,但是如果可能的话,我希望看到一个规范的解决方案(所以我可以学习规范的C ++方式)以及更多使用C ++中常见的任何其他库的实用解决方案,因此我也可以学习如何以更实际的方式完成它。
文本文件内容:
boost::trim_left()
现在解析文件的代码:
FILE_DESCRIPTION
523459 45267393
1 -91.1960210000 30.4248000000 6.9067078000
2 -91.1936990000 30.4238730000 0.2607690100
3 -91.1983420000 30.4257270000 11.4345030000
4 -91.2006640000 30.4266540000 8.2591810000
5 -91.2029850000 30.4275810000 2.2204340000
6 -91.2043510000 30.4258950000 3.0012660000
7 -91.1962610000 30.4231880000 13.4529710000
8 -91.1941710000 30.4215120000 7.8915730000
编码风格的评论也很受欢迎,因为我是C ++的新手,对我来说,一切都是粗糙的。请注意,为了简单起见,我已从示例中删除了文件打开检查语句和while {} EOF语句。
编辑1: 所以看起来之前发生的事情是相关的。我编辑了上面的问题,以反映同一问题的更准确版本。
答案 0 :(得分:3)
您已经拥有“规范C ++”方法。这是一个使用Boost Spirit Qi的演示:
<强> Live On Coliru 强>
#include <fstream>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
struct Fort14 {
std::string description;
int n_edges, n_points;
struct Point { double x,y,z; };
std::vector<Point> points;
};
BOOST_FUSION_ADAPT_STRUCT(Fort14::Point, x, y, z)
BOOST_FUSION_ADAPT_STRUCT(Fort14, description, n_edges, n_points, points)
Fort14 parse_fort14(std::istream& is) {
using It = boost::spirit::istream_iterator;
using namespace boost::spirit::qi;
rule<It, std::string()> description = *(char_ - eol);
It f(is >> std::noskipws), l;
Fort14 data;
if (phrase_parse(f, l,
description >> eol >>
int_ >> int_ >> eol >> // NE, NP
(omit[int_] >> auto_) % eol, // point data
blank, data))
{
return data;
}
auto frag = f;
for (int i = 10; i>0 && frag!=l; --i)
++frag;
throw std::runtime_error("Parse error at " + std::string(f, frag) + "...");
}
int main() {
std::ifstream ifs("input.txt");
auto parsed = parse_fort14(ifs);
std::cout << "Description: '" << parsed.description << "'\n";
std::cout << "n_edges: " << parsed.n_edges << "\n";
std::cout << "n_points: " << parsed.n_points << "\n";
for (auto& p : parsed.points)
std::cout << " - point { " << p.x << ", " << p.y << ", " << p.z << " }\n";
}
打印
Description: 'FILE_DESCRIPTION'
n_edges: 523459
n_points: 45267393
- point { -91.196, 30.4248, 6.90671 }
- point { -91.1937, 30.4239, 0.260769 }
- point { -91.1983, 30.4257, 11.4345 }
- point { -91.2007, 30.4267, 8.25918 }
- point { -91.203, 30.4276, 2.22043 }
- point { -91.2044, 30.4259, 3.00127 }
- point { -91.1963, 30.4232, 13.453 }
- point { -91.1942, 30.4215, 7.89157 }
我做了一些假设,但没有太多(你没有解释任何输入格式......)。 NE / NP可能是“边数,点数”的缩写(没有线索,真的)。
请注意
如果要验证点的索引是否依次增加,您可以:
(omit[int_(boost::phoenix::ref(counter)++)] >> auto_) % eol,
如果你想接受 n 点(例如n_points
或你的'NP'),你会写
repeat(n_points) [omit[int_] >> auto_ >> eol],
同时查看合并 Live On Coliru (其中只读取输入中的6个点,因为n_points
为6)。
答案 1 :(得分:2)
如果文件内容在每一行中具有相同的格式(int,double,double,double),则可以使用stream运算符,如下所示:
int no;
double d1, d2, d3;
filei >> no >> d1 >> d2 >> d3;
要读取整个文件,只需一个简单的while循环即可:
int main()
{
std::ifstream filei("/path/to/myInfo.txt");
int no;
double d1, d2, d3;
while (filei >> no >> d1 >> d2 >> d3) {
// do something with data
}
}
不需要花哨的解析。
要将行数据组合在一起,您可以使用结构代替并使用这些结构的向量:
struct row {
int no;
double x, y, z;
};
std::vector<row> rows;
// ...
row r;
while (filei >> r.no >> r.d1 >> r.d2 >> r.d3) {
rows.push_back(r);
}
下一步可能是为行结构实现流操作符:
std::istream &operator>>(std::istream &f, row &r)
{
return f >> r.no >> r.d1 >> r.d2 >> r.d3;
}
并在循环中使用它:
row r;
while (filei >> r) {
rows.push_back(r);
}
当您想要读取给定数量的行时,例如NP
行:
for (int i = 0; i < NP; ++i) {
// read and process line
}
虽然这是C ++ 101,你应该从书本或在线资源中学到它。