Hi I want to read data from a VTK file into my C++ program. Here is how my files will typically look.
POINTS 2 double
1 2
You could try some code that looks like this. It's kind of a combo of C and C++:
int main ()
{
//assuming that you've completely read in the file to a char* called myFileContents
char * token;
token = strtok (myFileContents," ");
while (token != NULL)
{
istringstream iss( token );
int readInData;
readInData << iss;
if(!iss){
//this means that the data wasn't numeric so don't do anything with it
}
else{
//data was numeric, store it how ever you want
}
token = strtok (NULL, " ");
}
return 0;
}
Once again I couldn't really resist the finger exercise in using Boost Spirit for this purpose.
Behold this very adhoc and minimalistic sample that
parses the given text (using Spirit Qi) into
does rudimentary error reporting on unpexpected input
prints the parsed data back into compact formatting (this uses Spirit Karma)
it is whitespace tolerant (though the newlines are required as in the input)
Flaws:
POINTS
_n
and POINT_DATA
n
are being handsomely ignored now)std::move
) to prevent the copying of the lookup table dataOutput of the code/input as shown (note the intentional 'bogus' input demonstrating the error reporting):
Parse failed remaining: 'bogus'
Points: [1.0,2.0], [3.0,4.0]
density: 7.0, 8.0
pressure: 5.0, 6.0
And the code (c++, tested with boost 1_47_0):
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
#include <map>
namespace qi = boost::spirit::qi;
namespace karma = boost::spirit::karma;
typedef std::vector<double> lookuptable_t;
typedef std::map<std::string, lookuptable_t> lookuptables_t;
typedef std::pair<double, double> point_t;
typedef std::vector<point_t> points_t;
int main()
{
std::string input =
"POINTS 2 double\n"
"1 2\n"
"3 4\n"
"POINT_DATA 2\n"
"SCALARS pressure double\n"
"LOOKUP_TABLE default\n"
"5\n"
"6\n"
"SCALARS density double\n"
"LOOKUP_TABLE default\n"
"7\n"
"8 bogus";
points_t points;
lookuptables_t lookuptables;
{
std::string::const_iterator f(input.begin()), l(input.end());
using namespace qi;
bool ok = phrase_parse(f, l,
"POINTS" > omit[ uint_ ] > "double" > eol >>
(double_ >> double_) % eol > eol >>
"POINT_DATA" > omit [ uint_ ],
char_(" \t"), points);
while (ok && f!=l)
{
std::string name;
lookuptable_t table;
ok = phrase_parse(f, l,
eol >> "SCALARS" > +raw [ eps >> "pressure"|"density" ] > "double" > eol >
"LOOKUP_TABLE" > "default" > eol >
double_ % eol,
char_(" \t"), name, table);
if (ok && !lookuptables.insert(std::make_pair(name, table)).second)
std::cerr << "duplicate table for '" << name << "' ignored" << std::endl;
}
if (!ok || (f!=l))
std::cerr << "Parse " << (ok?"success":"failed") << " remaining: '" <<
std::string(f, std::min(f+10, l)) << "'" << std::endl;
}
{
using namespace karma;
std::cout << format(
"Points: " << ('[' << double_ << ',' << double_ << ']') % ", " << eol <<
+(string << ": " << auto_ % ", " << eol),
points, lookuptables);
}
}
You can use the ignore
function to throw away lines of text that are not numbers. Use cin >> x
to read a value x from the input file. If that fails, the failbit
is set in the input stream, which you must clear
. Then, ignore the whole line.
std::vector<int> data;
while (!cin.eof())
{
int x;
if (cin >> x) {
data.push_back(x);
if (data.size() == 8)
{
// do whatever you need with the 8 numbers
data.clear();
}
} else {
cin.clear();
cin.ignore(1000, '\n'); // assuming maximum line length less than 1000
}
}
(This code assumes reading from cin
, which is redirected to another input file)