Best method for reading row and col of txt file - c++

Sorry, im a C++ noob! I have looked around for a solution but cant seem to find one that best suits my need. I am tring to read the width(max amount of char in line) and height (max amount of lines per file) of a txt file. Planning on using varaibles to help make dynamic sized txt files/levels.
I have had fixed width and height working previous to this!
TXT FILE: Simple output of chars for room layout (space=floor, #=wall, X=door):
########
# #
# X
# #
########
PROBLEM: Thought this to be a simple problem, but it only reads 2 of each variable(hNum,wNum)before breaking loop and program cant continue.
-What am i doing wrong?
-Should i be using seekg or different loop somehow?
-Do i need to alter my vector to 2D vector?
-Which is the best method for achieving this?
Room.cpp
//LOAD CURRENT ROOM FROM FILE
ss << RoomNo;
string str = ss.str();
string fname = ("Room");
fname.append(str);
fname.append(".txt");
infile.open(fname);
infile.clear();
infile.seekg(0);
if(infile.is_open())
{
// Sets width and height depndant on txt file size
string line;
//NOT WORKING!
while( !infile.eof())
{
hNum++;
getline ( infile, line);
wNum += line.length();
break;
}
height=hNum;
width=wNum;
//END
// Loop to end of file- to get you all the lines from txt file.
while(!infile.eof())
{
int i;
for(int row = 0; row < width; row++)
{
infile.getline(RoomFile, 256);
i = 0;
for(int col = 0; col < height; col++)
{
data.push_back(RoomFile[i]);
i++;
}
}
}
}
else
{
cout << "ERROR: infile not open" << endl;
}
infile.close();
UPDATE
This is what i got, tryin to do what Sky suggested...but cudnt work it all out. Then steped thro and thought the loop wasnt active so altered the argument. Now getting runtime error!
PROBLEM: Expression: vector subscript out of range!
Suggestions anyone?
string line;
while(getline(infile,line))
{
getline(infile, line);
tempVector.push_back(line);
}
width=line.length();
height=tempVector.size();

A possible way that can work would be to create a vector of strings and read the entire file, with each line a string in the vector.
Rough example:
#include <vector>
#include <string>
#include <fstream>
/* ... */
vector<string> content;
string buffer;
while(!infile.eof())
{
getline(infile, &string, '/n');
content.push_back(string);
}
width = findMaxLengthOfStrings(content);
height = content.size();
You are reading each line of the file as a separate string. The strings are pushed onto the vector. You can then easily find which string in the vector is longest, by iterating through the vector, using size(). The length in lines of the file is obtained with size() on the vector itself.
Also, posting just the relevant parts of the code, the I/O function, would have helped. Just saying ;) A small screen size and such.

Related

Reading from file into string while counting the lines C++

I am trying to read a file into a string array. But I want to do it as if I do not know what the length of the document is. so I want to get a while loop to count the lines, and then another one to read the document.
When I do this, it works fine but it assumes I know what the length is going to be for the size of the arrays.
string count_lines;//dummy string to read the line temp
string votes[11];
string ID[11];
string whole_line[11];
int i = 0;
while (getline(file, count_lines))
{
whole_line[i] = count_lines;
ID[i].assign(count_lines, 0, 4);
votes[i].assign(count_lines, 6, 4);
cout << count_lines << endl;
i++;
}
But i tried to do this variation but it just prints blank lines with the same function as i printed the option above
string count_lines;//dummy string to read the line temp
string votes[11];
string ID[11];
string whole_line[11];
int i = 0;
while (getline(file, count_lines))
{
i++;
}
int k = 0;
while (getline(file, count_lines) && k < i)
{
whole_line[k] = count_lines;
ID[k].assign(count_lines, 0, 4);
votes[k].assign(count_lines, 6, 4);
cout << count_lines << endl;
i++;
}
I am not sure what i'm doing wrong.
Each call to std::geline (as well as << operator and read method) advances input position stored in the stream object. In the first while loop, you read the entire file, so after this loop, input position indicator points to the end of the file.
In order to start reading from the beginning in the second loop, you have to reset the position back to 0, using the ifstream::seekg method. This way you'll be able to "re-read" the entire file.
On the other hand, as pointed out in the comments, this isn't really the best way to read a file into memory, line by line. It would probably be better to use std::vector to store lines and append lines read with getline to it. Alternatively, you could read the entire file at once into a single buffer and split it into lines.
If you really are just looking to get the number of lines in your file, it's far more efficient to read the entire file into a buffer all at once, then just count the number of newline characters contained within. The following code is one of the more efficient ways this could be done.
#include <vector>
#include <algorithm>
#include <fstream>
int main()
{
std::ifstream textFile("your_file.txt", std::ios::binary);
size_t fileSize = textFile.tellg();
textFile.seekg(0, std::ios::beg);
std::vector<char> buffer(fileSize);
size_t numLines(0);
if (textFile.read(buffer.data(), fileSize))
{
numLines = std::count(buffer.begin(), buffer.end(), '\n');
}
return 0;
}

Reading only numbers from a file, from a specific line

I am trying to read from a data file that contains a header which is 4 lines, and also has a list of numbers that I will be storing into a 2d int array
for example
header
header
header
header
int
int
int
int
......
I need to somehow skip these header lines which contain text and only use the int lines and store them into the aforementioned 2d array. When I open the file and search through it, it doesn't store any values at all because of the text at the very start. I've tried multiple if statements and other things to get around this, but has worked so far.
int main()
{
ifstream imageFile;
imageFile.open("myfile");
if (!imageFile.is_open())
{
exit (EXIT_FAILURE);
}
int test2[16][16];
int word;
imageFile >> word;
while (imageFile.good())
for (int i = 0; i < 16; i++)
{
for (int j = 0; j < 16; j++)
{
test2[i][j] = word;
imageFile >> word;
}
}
}
As said in the comments, you need to first read the headers - here I just store the headers in a trash variable which is a string that's being overwritten every time I store new header:
std::string trash;
for (int i =0; i < 4; i++)
std::getline(imageFile, trash);
This part goes after you check if file opened correctly and will be directly followed by your original code where you declare the 2D array and read the integers.
As it was also said in the comments you need std::getline that reads every header line as a whole and not a word at a time which was the first version of my answer (imageFile >> trash;).
You can do this just by regex and patterns (Modify code for 2d array this is just example for how you can extract numbers from file or string):
std::string ss;
ifstream myReadFile;
myReadFile.open("foo.txt");
char output[100];
if (myReadFile.is_open()) {
while (!myReadFile.eof()) {
myReadFile >> output;
ss.append(output);
ss.append("\n");
}
}
myReadFile.close();
std::regex rx(R"((?:^|\s)([+-]?[[:digit:]]+(?:\.[[:digit:]]+)?)(?=$|\s))"); // Declare the regex with a raw string literal
std::smatch m;
std::string str = ss;
while (regex_search(str, m, rx)) {
std::cout << "Number found: " << m[1] << std::endl; // Get Captured Group 1 text
str = m.suffix().str(); // Proceed to the next match
}
Output:
Number found: 612
Number found: 551
Number found: 14124

C++ Reading data from a file (containing spaces) line by line

I'm programming a game on a board 9x9 (which is a char 9x9 array). I wrote a method that saves the current game state in a file going according to the scheme bellow:
board.plansza[0][0]
board.plansza[0][1]
board.plansza[0][2]
board.plansza[0][3]
(...)
*points in int*
(Where every line is just a one character/space/number)
Now I need a method that's gonna read this file and put the data back in the same kind of array (if someone decided to stop playing, saved the game and then wanted to continue from previous state) as well as the variable for points.
The problem is that some of the lines in a saved file are just a space (' ') and all the methods I've tried are failing to read it properly because of that.
The latest way I tried (and failed):
for (int i = 0; i < ROZMIAR; i++){
for (int j = 0; j < ROZMIAR; j++){
zapis << board.plansza[i][j] << endl;
}
}
zapis << user.pkt << endl;
How do I read a file line by line if some lines contain only a space (which I don't want to ignore)?
Use getline(), like this:
#include <fstream>
#include <string>
int main()
{
std::ifstream infile("thefile.txt");
std::string line;
char matrix[10][2];
int i = 0;
while(std::getline(infile, line))
{
std:cout << line << std::endl;
if(line .find_first_not_of(' ') != std::string::npos)
{
// There's a non-space.
matrix[i++][0] = line[0];
}
}
return 0;
}

Why is the next line not executing C++

I have attached my full source code of my program that can open a .txt file. It doesn't execute after the cout << length. I am trying to store the .txt file information in memory by using an array.
#include <iostream>
#include <string.h>
#include <fstream>
using namespace std;
char filename[128];
char file[10][250];
int count;
int length;
string line;
int main ()
{
int count = 0;
int length = 0;
cout << "Filename: ";
cin.clear();
cin.getline(filename, sizeof(filename));
string new_inputfile(filename);
ifstream inputfiles (new_inputfile.c_str());
if(!inputfiles.is_open())
{
cout << "File could not be opened. \n ";
}
else
{
for (int i=0; getline(inputfiles,line); i++)
{
length++;
}
cout << length;
// char file[length][250]; <- How can I create the array based on the length variable?
// CODE DOES NOT EXECUTE AFTER THIS.
while(!inputfiles.eof() && (count<10))
{
inputfiles.getline(file[count],250);
count++;
}
for(int i=0; i < count; i++)
{
cout << file[i] << endl;
}
}
inputfiles.close();
return 0;
}
Also, since file[] is char, say for example file[1] contained the char Name=Mike, how do I strip off everything before the =. I want just Mike. I know with string, I can use substr() method, but I don't know for char.
This is horribly wasteful way to count number of lines in a file.
for (int i=0; getline(inputfiles,line); i++) // i is also completely useless here
{
length++;
}
You're reading the whole file only to throw everything away and start again! And after this loop is done, inputfiles.eof() will be true and you'll never enter neither the next while loop nor the last for loop (because i == count). Execution skips directly to inputfiles.close() and then you return from main.
I suggest you work on the line string as you go:
for ( ; getline(inputfiles, line); )
{
// do stuff with line and ditch the global char arrays
}
If you want store the lines for later, well, just save them :) The easiest thing to do is to use a vector:
std::vector<std::string> all_them_lines;
while (getline(file, line) all_them_lines.emplace_back(line);
There, the entire file is now saved in all_them_lines, line by line. You can access them just like you would in an array, like all_them_lines[0]. You also don't need to know the number of lines beforehand - vectors expand automatically when you add stuff to them.
Now to parse a line and extract formatted input from it, check out what stringstream class has to offer.
You asked:
// char file[length][250]; <- How can I create the array based on the length variable?
Declare file as:
char (*file)[250] = NULL;
and then,
file = new char[length][250];
Make sure you call delete [] file before the end of the function.
You said:
// CODE DOES NOT EXECUTE AFTER THIS.
You can rewind the stream and start reading from it again.
inputfiles.seekg(0);
count = 0;
while(!inputfiles.eof())
{
inputfiles.getline(file[count],250);
count++;
}

Reading data in from a .csv into usable format using C++

I would like to be able to read the data that I have into C++ and then start to do things to manipulate it. I am quite new but have a tiny bit of basic knowledge. The most obvious way of doing this that strikes me (and maybe this comes from using excel previously) would be to read the data into a 2d array. This is the code that I have so far.
#include <iostream>
#include <fstream>
#include <algorithm>
#include <string>
#include <sstream>
using namespace std;
string C_J;
int main()
{
float data[1000000][10];
ifstream C_J_input;
C_J_input.open("/Users/RT/B/CJ.csv");
if (!C_J_input) return -1;
for(int row = 0; row <1000000; row++)
{
string line;
getline(C_J_input, C_J, '?');
if ( !C_J_input.good() )
break;
stringstream iss(line);
for(int col = 0; col < 10; col++)
{
string val;
getline(iss, val, ',');
if (!iss.good() )
break;
stringstream converter(val);
converter >> data[row][col];
}
}
cout << data;
return 0;
}
Once I have the data read in I would like to be able to read through it line by line and then pull analyse it, looking for certain things however I think that could probably be the topic of another thread, once I have the data read in.
Just let me know if this is a bad question in any way and I will try to add anything more that might make it better.
Thanks!
as request of the asker, this is how you would load it into a string, then split into lines, and then further split into elements:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <sstream>
//This takes a string and splits it with a delimiter and returns a vector of strings
std::vector<std::string> &SplitString(const std::string &s, char delim, std::vector<std::string> &elems)
{
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delim))
{
elems.push_back(item);
}
return elems;
}
int main(int argc, char* argv[])
{
//load the file with ifstream
std::ifstream t("test.csv");
if (!t)
{
std::cout << "Unknown File" << std::endl;
return 1;
}
//this is just a block of code designed to load the whole file into one string
std::string str;
//this sets the read position to the end
t.seekg(0, std::ios::end);
str.reserve(t.tellg());//this gives the string enough memory to allocate up the the read position of the file (which is the end)
t.seekg(0, std::ios::beg);//this sets the read position back to the beginning to start reading it
//this takes the everything in the stream (the file data) and loads it into the string.
//istreambuf_iterator is used to loop through the contents of the stream (t), and in this case go up to the end.
str.assign((std::istreambuf_iterator<char>(t)),
std::istreambuf_iterator<char>());
//if (sizeof(rawData) != *rawSize)
// return false;
//if the file has size (is not empty) then analyze
if (str.length() > 0)
{
//the file is loaded
//split by delimeter(which is the newline character)
std::vector<std::string> lines;//this holds a string for each line in the file
SplitString(str, '\n', lines);
//each element in the vector holds a vector of of elements(strings between commas)
std::vector<std::vector<std::string> > LineElements;
//for each line
for (auto it : lines)
{
//this is a vector of elements in this line
std::vector<std::string> elementsInLine;
//split with the comma, this would seperate "one,two,three" into {"one","two","three"}
SplitString(it, ',', elementsInLine);
//take the elements in this line, and add it to the line-element vector
LineElements.push_back(elementsInLine);
}
//this displays each element in an organized fashion
//for each line
for (auto it : LineElements)
{
//for each element IN that line
for (auto i : it)
{
//if it is not the last element in the line, then insert comma
if (i != it.back())
std::cout << i << ',';
else
std::cout << i;//last element does not get a trailing comma
}
//the end of the line
std::cout << '\n';
}
}
else
{
std::cout << "File Is empty" << std::endl;
return 1;
}
system("PAUSE");
return 0;
}
On second glance, I've noticed few obvious issues which will slow your progress greatly, so I'll drop them here:
1) you are using two disconnected variables for reading the lines:
C_J - which receives data from getline function
line - which is used as the source of stringstream
I'm pretty sure that the C_J is completely unnecessary. I think you wanted to simply do
getline(C_J_input, line, ...) // so that the textline read will fly to the LINE var
// ...and later
stringstream iss(line); // no change
or, alternatively:
getline(C_J_input, C_J, ...) // no change
// ...and later
stringstream iss(C_J); // so that ISS will read the textline we've just read
elsewise, the stringstream will never see what getline has read form the file - getline writes the data to different place (C_J) than the stringstream looks at (line).
2) another tiny bit is that you are feeding a '?' into getline() as the line separator. CSVs usually use a 'newline' character to separate the data lines. Of course, your input file may use '?' - I dont know. But if you wanted to use a newline instead then omit the parameter at all, getline will use default newline character matching your OS, and this will probably be just OK.
3) your array of float is, um huge. Consider using list instead. It will nicely grow as you read rows. You can even nest them, so list<list<float>> is also very usable. I'd actually probably use list<vector<float>> as the number of columns is constant though. Using a preallocated huge array is not a good idea, as there always be a file with one-line-too-much you know and ka-boom.
4) your code contains a just-as-huge loop that iterates a constant number of times. A loop itself is ok, but the linecount will vary. You actually don't need to count the lines. Especially if you use list<> to store the values. Just like you;ve checked if the file is properly open if(!C_J_input), you may also check if you have reached End-Of-File:
if(C_J_input.eof())
; // will fire ONLY if you are at the end of the file.
see here for an example
uh.. well, that's for start. Goodluck!