I have created code that will execute a file and then will execute code and store that code into a .csv filer shown below
#include <string>
#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <fstream>
using namespace.std;
int main(){
int foo = 10;
for(int i =1; x<=8 x++){
std::stringstream ss;
ss << "echo " << foo << " | ./triad >> scaling.csv"<<'\n';
std::cout << ss.str().c_str() <<std::endl;
system(ss.str().c_str());
foo=foo*10
}
return 0;
}
The triad program is one that I am given and cannot change. I run basically 10 iterations on it and print the output of that to a scaling.csv, to give me the following output
Length: 10 MFLOP/s: 2541.29
Length: 100 MFLOP/s: 2515.85
Length: 1000 MFLOP/s: 3616.75
and so on...
does anyone know how to parse that file so instead my scaling.csv will look something like this
Key,Value
10,2541.29
100,2515.85
1000,3616.75
Again what gets printed out by triad I cannot change.
Simple:
int main()
{
string s;
int key; float val;
ifstream out("out.txt");
ofstream in("in.txt);
in >> s;
in >> key; // key == 10
in >> s;
in >> val; // val == 2541.29
}
Put this into a function and you have:
void extract(std::istream& in, int& key, float& val)
{
// same as above
}
int main()
{
int key; float val;
while (in)
{
extract(in, key, val);
out << key << ", " << val << std::endl;
}
}
But we're performing the input after we check the stream. This can cause problems. Let's have the extract function return a reference to the stream:
std::ios& extract(std::istream& in, int& key, float& val)
{
// same as above
}
int main()
{
int key; float val;
while (extract(in, key, val))
// ^^^^^^^^^^^^^^^^^^^^^
{
out << key << ", " << val << std::endl;
}
}
Related
I am trying to parse through a gcode and I want to extract only the x & y coordinates of G1 from each line
GCODE EXAMPLE
G1 X123.456 Y125.425 Z34.321
I tried the basic getline() function but it prints the whole line, don't understand how to add filters to the getline() to just extract only x & y numerical values and only for lines with G1 on start.
#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>
#include <fstream>
using std::cout; using std::cerr;
using std::endl; using std::string;
using std::ifstream; using std::vector;
int main()
{
string filename("test1.gcode");
vector<string> lines;
string line;
ifstream input_file(filename);
if (!input_file.is_open()) {
cerr << "Could not open the file - '"
<< filename << "'" << endl;
return EXIT_FAILURE;
}
while (getline(input_file, line)){
lines.push_back(line);
}
for (const auto &i : lines)
cout << i << endl;
input_file.close();
return EXIT_SUCCESS;
}
You cannot add filters to getline(). It will always return the complete next line in the input.
What you can do is parse this line yourself, and extract the values that you need.
This is can be done in multiple ways. One of them is demonstrated below.
I used std::string::find to get an offset for the character 'X'/'Y' marking the x/y coordinates.
Then I used std::atof to convert the relevant part of the line to a double value.
I also used std::string::find to check whether the line starts with the required prefix for this command.
#include <string>
#include <iostream>
#include <cstdlib>
int main()
{
std::string line = "G1 X123.456 Y125.425 Z34.321";
if (line.find("G1") == 0)
{
size_t xpos = line.find('X');
if (xpos == std::string::npos) { /* handle error */ }
double x = std::atof(line.data() + xpos + 1); // skip over the 'X'
size_t ypos = line.find('Y');
if (ypos == std::string::npos) { /* handle error */ }
double y = std::atof(line.data() + ypos + 1); // skip over the 'Y'
std::cout << "X: " << x << ", Y: " << y << std::endl;
}
}
Output:
X: 123.456, Y: 125.425
The usual way to handle structured data is... with a struct.
struct line_item {
int g;
double x;
double y;
double z;
};
std::istream& operator>>(std::istream& in, line_item& item) {
line_item temp;
item = {};
in >> 'G' >> temp.g >> 'X' >> temp.x >> 'Y' >> temp.y >> 'Z' >> temp.z;
if (in)
item = temp;
return in;
}
std::ostream& operator<<(std::ostream& out, const line_item& item) {
return out << 'G' << item.g << " X" << item.x << " Y" << item.y << " Z" << item.z;
}
Normally one can't istream >> 'G', so I have a helper for that.
//helper function for "reading in" character literals
template<class e, class t>
std::basic_istream<e,t>& operator>>(std::basic_istream<e,t>& in, const e& char_literal) {
e buffer; //get buffer
in >> buffer; //read data
if (buffer != char_literal) //if it failed
in.setstate(in.rdstate() | std::ios::failbit); //set the state
return in;
}
http://coliru.stacked-crooked.com/a/6af1f3c881cc9e6e
Then you read in the items using the normal istream>>line_item, and from there, you have structured data that you can do whatever you want with, such as creating a secondary struct that only stores the items you care about.
I have a txt file which contains two txt file references ei. main.txt contains eg1.txt and eg2.txt and i have to access the content in them and find the occurences of every word and return a string with the word and the documents it was preasent in(0 being eg1.txt and 1 being eg2.txt). My program compiles but I can't get past the first word I encounter. It gives the right result (word: 0 1) since the word is preasent in both the files and in the first position but it doesn't return the other words. Could someone please help me find the error? Thank you
string func(string filename) {
map<string, set<int> > invInd;
string line, word;
int fileNum = 0;
ifstream list (filename, ifstream::in);
while (!list.eof()) {
string fileName;
getline(list, fileName);
ifstream input_file(fileName, ifstream::in); //function to iterate through file
if (input_file.is_open()) {
while (getline(input_file, line)) {
stringstream ss(line);
while (ss >> word) {
if (invInd.find(word) != invInd.end()) {
set<int>&s_ref = invInd[word];
s_ref.insert(fileNum);
}
else {
set<int> s;
s.insert(fileNum);
invInd.insert(make_pair<string, set<int> >(string(word) , s));
}
}
}
input_file.close();
}
fileNum++;
}
Basically your function works. It is a little bit complicated, but i works.
After removing some syntax errors, the main problem is, that you do return nothing from you function. There is also no output statement.
Let me show you you the corrected function which shows some output.
#include <string>
#include <map>
#include <iostream>
#include <fstream>
#include <set>
#include <sstream>
#include <utility>
using namespace std;
void func(string filename) {
map<string, set<int> > invInd;
string line, word;
int fileNum = 0;
ifstream list(filename, ifstream::in);
while (!list.eof()) {
string fileName;
getline(list, fileName);
ifstream input_file(fileName, ifstream::in); //function to iterate through file
if (input_file.is_open()) {
while (getline(input_file, line)) {
stringstream ss(line);
while (ss >> word) {
if (invInd.find(word) != invInd.end()) {
set<int>& s_ref = invInd[word];
s_ref.insert(fileNum);
}
else {
set<int> s;
s.insert(fileNum);
invInd.insert(make_pair(string(word), s));
}
}
}
input_file.close();
}
fileNum++;
}
// Show the output
for (const auto& [word, fileNumbers] : invInd) {
std::cout << word << " : ";
for (const int fileNumber : fileNumbers) std::cout << fileNumber << ' ';
std::cout << '\n';
}
return;
}
int main() {
func("files.txt");
}
This works, I tested it. But maybe you want to return the findings to your main function. Then you should write:
#include <string>
#include <map>
#include <iostream>
#include <fstream>
#include <set>
#include <sstream>
#include <utility>
using namespace std;
map<string, set<int> > func(string filename) {
map<string, set<int> > invInd;
string line, word;
int fileNum = 0;
ifstream list(filename, ifstream::in);
while (!list.eof()) {
string fileName;
getline(list, fileName);
ifstream input_file(fileName, ifstream::in); //function to iterate through file
if (input_file.is_open()) {
while (getline(input_file, line)) {
stringstream ss(line);
while (ss >> word) {
if (invInd.find(word) != invInd.end()) {
set<int>& s_ref = invInd[word];
s_ref.insert(fileNum);
}
else {
set<int> s;
s.insert(fileNum);
invInd.insert(make_pair(string(word), s));
}
}
}
input_file.close();
}
fileNum++;
}
return invInd;
}
int main() {
map<string, set<int>> data = func("files.txt");
// Show the output
for (const auto& [word, fileNumbers] : data) {
std::cout << word << " : ";
for (const int fileNumber : fileNumbers) std::cout << fileNumber << ' ';
std::cout << '\n';
}
}
Please enable C++17 in your compiler.
And please see below a brushed up solution. A little bit cleaner and compacter, with comments and better variable names.
#include <string>
#include <map>
#include <iostream>
#include <fstream>
#include <set>
#include <sstream>
#include <utility>
using WordFileIndicator = std::map<std::string, std::set<int>>;
WordFileIndicator getWordsWithFiles(const std::string& fileNameForFileLists) {
// Here will stor the resulting output
WordFileIndicator wordFileIndicator{};
// Open the file and check, if it could be opened
if (std::ifstream istreamForFileList{ fileNameForFileLists }; istreamForFileList) {
// File number Reference
int fileNumber{};
// Read all filenames from the list of filenames
for (std::string fileName{}; std::getline(istreamForFileList, fileName) and not fileName.empty();) {
// Open the files to read their content. Check, if the file could be opened
if (std::ifstream ifs{ fileName }; ifs) {
// Add word and associated file number to set
for (std::string word{}; ifs >> word; )
wordFileIndicator[word].insert(fileNumber);
}
else std::cerr << "\n*** Error: Could not open '" << fileName << "'\n\n";
// Continue with next file
++fileNumber;
}
}
else std::cerr << "\n*** Error: Could not open '" << fileNameForFileLists << "'\n\n";
return wordFileIndicator;
}
// Some test code
int main() {
// Get result. All words and in which file they exists
WordFileIndicator data = getWordsWithFiles("files.txt");
// Show the output
for (const auto& [word, fileNumbers] : data) {
std::cout << word << " : ";
for (const int fileNumber : fileNumbers) std::cout << fileNumber << ' ';
std::cout << '\n';
}
}
There would be a much faster solution by using std::unordered_map and std::unordered_set
Please make sure your code is composed from many small functions. This improves readability, it easier to reason what code does, in such form parts of code can be reused in alternative context.
Here is demo how it can looks like and why it is better to have small functions:
#include <algorithm>
#include <filesystem>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <string>
#include <unordered_map>
#include <vector>
struct FileData
{
std::filesystem::path path;
int index;
};
bool operator==(const FileData& a, const FileData& b)
{
return a.index == b.index && a.path == b.path;
}
bool operator!=(const FileData& a, const FileData& b)
{
return !(a == b);
}
using WordLocations = std::unordered_map<std::string, std::vector<FileData>>;
template<typename T>
void mergeWordsFrom(WordLocations& loc, const FileData& fileData, T b, T e)
{
for (; b != e; ++b)
{
auto& v = loc[*b];
if (v.empty() || v.back() != fileData)
v.push_back(fileData);
}
}
void mergeWordsFrom(WordLocations& loc, const FileData& fileData, std::istream& in)
{
return mergeWordsFrom(loc, fileData, std::istream_iterator<std::string>{in}, {});
}
void mergeWordsFrom(WordLocations& loc, const FileData& fileData)
{
std::ifstream f{fileData.path};
return mergeWordsFrom(loc, fileData, f);
}
template<typename T>
WordLocations wordLocationsFromFileList(T b, T e)
{
WordLocations loc;
FileData fileData{{}, 0};
for (; b != e; ++b)
{
++fileData.index;
fileData.path = *b;
mergeWordsFrom(loc, fileData);
}
return loc;
}
WordLocations wordLocationsFromFileList(std::istream& in)
{
return wordLocationsFromFileList(std::istream_iterator<std::filesystem::path>{in}, {});
}
WordLocations wordLocationsFromFileList(const std::filesystem::path& p)
{
std::ifstream f{p};
f.exceptions(std::ifstream::badbit);
return wordLocationsFromFileList(f);
}
void printLocations(std::ostream& out, const WordLocations& locations)
{
for (auto& [word, filesData] : locations)
{
out << std::setw(10) << word << ": ";
for (auto& file : filesData)
{
out << std::setw(3) << file.index << ':' << file.path << ", ";
}
out << '\n';
}
}
int main()
{
auto locations = wordLocationsFromFileList("files.txt");
printLocations(std::cout, locations);
}
https://wandbox.org/permlink/nBbqYV986EsqvN3t
I need to create a sort algorithm that takes an array called myArray where there is information from a txt file called start.txt. The problem is that I have inside the txt file many vectors like this: 2 2 30 30, where the first number is the robot number, the second the team, and the last two are the x and y position. I only need to order them in ascending order taking the robot number, but the output has to be the whole vector. Any ideas on how to do it?
#include "robot.h"
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <sstream>
#include <cstring>
#include <vector>
//class Robot {
// std::string robotNum;
// std::string robotTeam;
// std::string robotPosX;
// std::string robotPosY;
// public:
// Robot(std::string robotNum, std::string robotTeam, std::string robotPosX, std::string robotPosY) {
// this->robotNum = robotNum;
// this->robotTeam = robotTeam;
// this->robotPosX = robotPosX;
// this->robotPosY = robotPosY;
// }
// std::string getRobotNum() {
// return this->robotNum;
// }
// void setRobotNum(std::string robotNum) {
// this->robotNum;
// }
//};
//void bubbleSort(std::vector<Robot> myArray, int n) {
//int i, j;
//for (i= 0; i<n-1; i++)
//}
using namespace std;
string line;
std::vector<robot> myArray;
//string* sortArray(string* myArray) {
//bool sortByNum(const robot& lhs, const robot& rhs) { return lhs.robotNum < rhs.robotNum; }
//return myArray;
//}
void show() {
ifstream myfile;
myfile.open("start.txt");
//string line;
//std::vector<robot> myArray;
while (getline(myfile, line))
{
std::istringstream iss(line);
string line;
std::string segment;
std::vector<std::string> seglist;
while (std::getline(iss, segment, ' '))
{
seglist.push_back(segment);
}
//std::vector<robot> myArray;
robot robot(seglist[0], seglist[1], seglist[2], seglist[3]);
myArray.push_back(robot);
cout << seglist[0] << " " << seglist[1] << " " << seglist[2] << " " << seglist[3] << "\n";
//myArray[0].getRobotNum();
//for (robot &r : myArray)
// std::cout << r.getRobotNum() << " _ " << std::endl;
//for (unsigned int i = 0; i <= unsigned(myArray.size()); i++) {
//}
cout << "\n";
}
//cout << myArray[];
myfile.close();
}
int main()
{
show();
return 0;
}
Use std::sort with a custom comparator that only looks at the robot number
#include <algorithm>
std::vector<robot> myArray;
...
sort(myArray.begin(), myArray.end(),
[](const robot& x, const robot& y) { return x.getRobotNum() < y.getRobotNum(); }
);
The piece starting with [] is a lambda function that compares two robots using the robot number. This function is passed to std::sort which uses it to sort your vector.
I'm trying to read the following maze.txt file:
35
35
0
10
++++++++++S++++++++++++++++++++++++
++++++++++OOOOOOOOOOOOOOOOOOOOOOOOO
++++++++++O++++++++++++++++++O+++++
OOOOOOOOOOOOOOOOOOOOOOOOOO+++O++OOE
O+++++++++O++++++++++++++O+++O++O++
OOOOOO++++O++++++++++++++O+++O++O++
O++++O++++OOOOOOOOOOO++++O+OOO++O++
O++++O++++O+++++++++OOOO+O+++O++O++
OOO++OOOO+OOOOOO+++++++++++OOO++OOO
O+O+++++O++++++OOOOOOOOOO++O++++++O
O+OOOO++O++++++O++++++++O+++OOO+++O
O++++O++OOOOOOOO++++++++O+++O+O+++O
OOO++O++++++++++++++++++OOOOO+O+++O
++O++OOOOOOOOOOOOOOOO+++++++++OO++O
OOO+++++++++++++++++OOOOOO++++++++O
O++++++++++++++++++++++++O++OOOOOOO
+++++++++++++++++++++++++O++O++++++
OOOOOOOOOOOOOOOOOOOOOOOOOO++OOOOO++
O++++++++++++++++++++++++O++++++O++
OOOOOOO+++++++++++++++OOOOOOO+++O++
++++++++++++++++++++++O+++++OO++O++
OOOOOOOOOOOOOOOOOOOOOOO++++++O++O++
O++++++++++++++++++++++++++++O+OOOO
OOOO++++++++++++++++++++OOOOOO+O+++
+++OOOOOOOOO+++++++++++++++++++O+++
+++++O+++++OOOOOOOOOO++++++++OOO+++
+O+++OOOOO++++++O++++++++++++O+++++
+OOOOO+++O++++++OOOOOO+++++++O+++++
+++++++++++++++++++++OOOOOOOOO+++++
OOOOOOOOOOOOOOOOOOOOOO+++++++++++++
+++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++
The code works fine with the maze inside the code but I moved it out to a text file, which seems to be read but it is not working. It's giving me the error:
No matching function for call to 'mazeTravel'.
I'm not sure where to go from here. Any help would be appreciated!
#include <iostream>
#include <fstream>
using namespace std;
void printMaze(const char maze[][12], int xCoordinate, int yCoordinate);
int mazeTravel(char maze[][12], int xCoordinate, int yCoordinate, int direction);
int main()
{
char maze[35][35];
ifstream file;
file.open("maze.txt");
if (!file) {
cout << "Error reading file\n";
return -1;
}
else {
for (int row = 0; row < 35; row++) {
for (int column = 0; column < 35; column++) {
file >> maze[row][column];
int success = 0;
success = mazeTravel(maze, 2, 0, 1);
if (success == 1)
cout << "The maze has been solved.\n";
else
cout << "Sorry, the maze cannot be solved\n";
}
}
}
return 0;
}
You could use a std::vector of std::strings to represent your maze:
std::vector<std::string> maze;
To access its cells use
maze[row][column]; // with row being y and column x
To get the number of rows use
maze.size()
and
maze[0].size()
for the number of columns.
You could read such a maze like that (without error checking to not clutter the code):
std::vector<std::string> readMaze(std::istream &is)
{
std::size_t columns;
std::size_t rows;
is >> columns >> rows;
int foo; // sorry, don't know what the 3rd and 4th
is >> foo >> foo; // number is. a starting position, perhaps?
// ignore the rest of the current line:
is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::string line;
std::vector<std::string> maze;
while (std::getline(is, line))
maze.push_back(line);
return maze;
}
An implementation (with error checking) could look like that:
#include <cstdlib> // EXIT_FAILURE
#include <limits> // std::numeric_limits<>
#include <vector>
#include <string>
#include <fstream>
#include <iostream>
// to not have to type std::vector<std::string> all over the place
using maze_type = std::vector<std::string>;
void printMazeCell(maze_type const &maze, std::size_t x, std::size_t y)
{
std::cout.put(maze[y][x]);
}
void printMaze(maze_type const &maze)
{
for (auto const &row : maze)
std::cout << row << '\n';
}
int mazeTravel(maze_type const &maze, std::size_t x, std::size_t y, int dir)
{
// access cells of the maze with maze[y][x]
// maze.size() for the number of columns and
// maze[0].size() for the number of rows
return 42;
}
maze_type readMaze(std::istream &is)
{
std::size_t columns;
if (!(is >> columns)) {
std::cerr << "Couldn't read the number of columns :(\n\n";
return maze_type{}; // return an empty maze on error
}
std::size_t rows;
if (!(is >> rows)) {
std::cerr << "Couldn't read the number of rows :(\n\n";
return maze_type{};
}
int foo;
is >> foo >> foo; // sorry, don't know what the 3rd and 4th number is
// ignore the rest of the current line:
is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Trying to read a maze with " << columns << " columns ...\n";
std::string line;
maze_type maze;
while (std::getline(is, line)) {
if (line.length() != columns) {
std::cerr << "Found a row that contains only "
<< line.length() << " columns :(\n\n";
return maze_type{};
}
maze.push_back(line);
}
if (maze.size() != rows) {
std::cerr << "The maze only consists of "
<< maze.size() << " rows :(\n\n";
return maze_type{};
}
return maze;
}
int main()
{
char const *filename = "maze.txt";
std::ifstream is{ filename };
if (!is.is_open()) {
std::cerr << "Couldn't open \"" << filename << "\" for reading :(\n\n";
return EXIT_FAILURE;
}
maze_type maze = readMaze(is);
if (!maze.size()) { // readMaze returned an empty maze :(
std::cerr << "Bye.\n";
return EXIT_FAILURE;
}
printMaze(maze);
}
The problem that you don't have the implementation of
int mazeTravel(char maze[][12], int xCoordinate, int yCoordinate, int direction);
You should create the implementation like this:
int mazeTravel(char maze[][12], int xCoordinate, int yCoordinate, int direction)
{
// The implementation
return 0;
}
Another thing: You have to read the first some numbers at the beginning of the file.
35
35
0
10
After that you can read the matrix from the file
here is my problem. i have some two dimensional data with changing dimensionality, that i want to read into an 2d-array of doubles. Furthermore, there are at some points not number in the file but "NaN"s, that i want to be replaced by a zero. I made my code working so far, but i only managed to read integers. Maybe you could help me out to read it as doubles?
Here is what i got so far:
void READER(char filepath [], int target [129][128])
{
//---------------------------- header double & int
int rowA = 0;
int colA = 0;
std::string line;
std::string x;
std::cout << "reading file: " << filepath << "\n";
std::cout << std::endl;
std::ifstream fileIN;
fileIN.open(filepath);
if (!fileIN.good())
std::cerr << "READING ERROR IN FILE: " << filepath << std::endl;
while (fileIN.good())
{
while (getline(fileIN, line))
{
std::istringstream streamA(line);
colA = 0;
while (streamA >> x)
{
boost::algorithm::replace_all(x, "NaN", "0");
boost::algorithm::replace_all(x, ",", ""); //. rein
// std::cout << string_to_int(x) << std::endl;
target [rowA][colA] = string_to_int(x);
colA++;
}
rowA++;
if(rowA%5 ==0)
{
std::cout << "*";
}
}
}
std::cout << " done." <<std::endl;
}
this writes the files into 'target'. The function string to int looks the following:
int string_to_int (const std::string& s)
{
std::istringstream i(s);
int x;
if(!(i >> x))
return 0;
return x;
}
here you find some example data:
"exactly, thats what i thought about doing with the line boost::algorithm::replace_all(x, ",", ""); by replacing , by ."
Use following function to convert to any type, say double :-
template <typename T>
T StringToNumber ( const std::string &Text )
{
std::istringstream ss(Text);
T result;
return ss >> result ? result : 0;
}
Call using :
boost::algorithm::replace_all(x, ",", "."); // Change , to .
std::cout << StringToNumber<double>(x) << std::endl;
Or
you can simply use boost::lexical_cast
std::cout<<boost::lexical_cast<double>( x )<<std::endl;
Make sure you have a double 2D array