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;
}
Related
I need to find the
- average length of all the words
- the shortest and longest word length; and
- how many words are
in a separate text file, using c++. There are 79 words in the file and it is called "test.txt."
what i have so far is
#include <bits/stdc++.h>
#include <cstdio>
using namespace std;
int main()
{
FILE* fp;
char buffer[100];
fp = fopen("test.txt", "r");
while (!feof(fp)) // to read file
{
// fucntion used to read the contents of file
fread(buffer, sizeof(buffer), 100, fp);
cout << buffer;
}
return 0;
}
All this does is print out the words that are in the file.
I am using an online compiler until i can get to my desktop with visual studio 2017 later today
Well, with c++ instead of FILE* rather use a std::ifstream, a std::string word; variable and formatted text extraction operator>>() to read single words from the file in a loop:
std::ifstream infile("test.txt");
std:string word;
while(infile >> word) {
}
Count every word read from the file in a variable int wordCount;
int wordCount = 0;
while(infile >> word) {
++wordCount;
}
Sum up the character lengths of the read words in another variable int totalWordsCharacters; (you can use the std::string::length() function to determine the number of characters used in a word).
int totalWordsCharacters = 0;
while(infile >> word) {
totalWordsCharacters += word.length();
}
After you completed reading that file, you can easily compute the average length of words by dividing
int avgCharacterPerWord = totalWordsCharacters / wordCount;
Here's a complete working example, the only difference is the '\n' in your input file format was replaced by a simple blank character (' ').
If you want to have the average between ALL the words, you have to add all lengths together and divide it by the number of words in your file (You said 79 words)
But if you want to get the average between only the shortest word and the longest one you will have to first: Get those words.
You can do that by simply use two counters as you go through all words. The first counter will be set to the length of the current word if it has a smaller length as the first counter. The second counter will be set to the length of the current word if it has a grater length as the second counter.
Then you will add those two counters together and divide them by 2.
Your problem is that you are writing C Code. This makes the problem harder.
In C++ reading a list of words from a file is simple using the >> operator.
std::ifstream file("FileName");
std::string word;
while(file >> word)
{
// I have read another word from the file.
// Do your calculations here.
}
// print out your results here after the loop.
Note the >> operator treats end of line just like a space and simply ignores it (It acts like a word separator).
I have learned my lesson, so i will be short, and to the subiect.
I need a function, in my class, that can read a file line by line, and store them into a array/string so i can use it.
I have the following example( please don`t laugh, i am a begginer):
int CMYCLASS::LoadLines(std::string Filename)
{
std::ifstream input(Filename, std::ios::binary | ios::in);
input.seekg(0, ios::end);
char* title[1024];
input.read((char*)title, sizeof(int));
// here what ?? -_-
input.close();
for (int i = 0; i < sizeof(title); i++)
{
printf(" %.2X ";, title[i]);
}
printf("\");
return 0;
}
I'm not sure exactly what your are asking.
However - below is some code that reads a file line-by-line and stores the lines in a vector. The code also prints the lines - both as text lines and the integer value of each character. Hope it helps.
int main()
{
std::string Filename = "somefile.bin";
std::ifstream input(Filename, std::ios::binary | ios::in); // Open the file
std::string line; // Temp variable
std::vector<std::string> lines; // Vector for holding all lines in the file
while (std::getline(input, line)) // Read lines as long as the file is
{
lines.push_back(line); // Save the line in the vector
}
// Now the vector holds all lines from the file
// and you can do what ever you want it
// For instance we can print the lines
// Both as a line and as the hexadecimal value of every character
for(auto s : lines) // For each line in vector
{
cout << s; // Print it
for(auto c : s) // For each character in the line
{
cout << hex // switch to hexadecimal
<< std::setw(2) // print it in two
<< std::setfill('0') // leading zero
<< (unsigned int)c // cast to get the integer value
<< dec // back to decimal
<< " "; // and a space
}
cout << endl; // new line
}
return 0;
}
I do not laugh due to your original code - no way - I was also a beginner once. But your code is c-style code and contains a lot of bugs. So my advice is: Please use c++ style instead. For instance: never use the C-style string (i.e. char array). It is so error prone...
As you are a beginner (your own words :) let me explain a few things about your code:
char* title[1024];
This is not a string. It is 1024 pointers to characters which can also by 1024 pointers to c-style strings. However - you have not reserved any memory for holding the strings.
The correct way would be:
char title[1024][256]; // 1024 lines with a maximum of 256 chars per line
Here you must make sure that the input file has less than 1024 lines and that each line each less than 256 chars.
Code like that is very bad. What to do if the input file has 1025 lines?
This is where c++ helps you. Using std::string you don't need to worry about the length of the string. The std::string container will just adjust to the size you put into in to it.
The std::vector is like an array. But without a fixed size. So you can just keep adding to it and it will automatically adjust the size.
So c++ offers std::string and std::vector to help you to handle the dynamic size of the input file. Use it...
Good luck.
I am writing a program that extracts data from a text file and encrypts it. I am having some trouble with this. First of all there is an error at the getline(data,s[i]) part. Also the text file has two sentences but it only encrypts the second sentence. The other issue with that is It encrypts one letter at a time and outputs the sentence every time. It should output just the sentence encrypted.
#include <iostream>
#include <fstream>
#include <istream>
using namespace std;
int main(){
//Declare Variables
string s;
ifstream data;
//Uses Fstream to open text file
data.open ("/Users/MacBookPro/Desktop/data.txt");
// Use while loop to extract the data from the text file
while(!data.eof()){
getline(data,s);
cout<< s << endl;
}
//Puts the data from the text file into a string array
for(int i = 0; data.good(); i++){
getline(data, s[i]);
cout<< s <<endl;
}
// encrypts the string
if(data.is_open()){
for(int i = 0; i < s.length();i++){
s[i] += 2;
cout << s << endl;
}
}
return 0;
}
In the code below you already reach the end of the stream, and store the last line on the string s.
while(!data.eof()){
getline(data,s);
cout<< s << endl;
}
My suggestion is that you use a list of strings.
vector< string > s;
string tmp;
while(!data.eof()){
getline(data,tmp);
s.push_back(tmp);
cout<< s << endl;
}
The next step you loop through the list and do the encryption
for(i=0; i < s.size(); i++)
{
// encrypt s[i]
}
Hope this helped!
First I had to add this line to get "getline" to be recognised:
#include <string>
Then, there was indeed an error with the line:
getline(data, s[i]);
This is a compilation error, that function is expecting a stream and a string, but you pass it a stream and a char.
Changing that line for:
getline(data, s);
makes your program compile.
However it probably does not do what you want at this point, since the variable i from the for is being ignored.
I suggest that you check out some documentation on the getline function, then rethink what you want to do and try again.
You can fine some doc here:
https://msdn.microsoft.com/en-us/library/vstudio/2whx1zkx(v=vs.100).aspx
Your other concern was that it output your string many times. This is normal, since your cout statement is inside in your encryption loop.
Move it outside the loop instead, to output it only one time once the encryption loop is done.
It is important to spend the time to understand what each line of your program is doing, and why you need it to achieve your goal.
Also when doing something that we find complicated, its easier to do one small part of it at a time, make sure it works, then continue with the next part.
Good Luck :)
Create a temporary string for containing each line and an integer since we're going to find the total number of lines to create an array for all of them.
string temp = "";
int numberOfLines = 0;
Now we try to find the total number of lines
while(data.good()) {
getline(data, temp);
cout << temp << endl;
numberOfLines++;
}
Now we can create an array for all of the lines. This is a dynamic array which you can read on it for more information.
string * lines = new string[numberOfLines];
Now is the time to roll back and read encrypt all the lines. But first we have to go back to first position of file. That's why we use seekg
data.seekg(data.beg);
For each line we read, we'll put in the array and loop through each character, encrypt it and then show the whole sentence.
int i = 0;
while (data.good()) {
getline(data, lines[i]);
i++;
for (int j = 0; lines[i].size(); j++ ) {
lines[i].at(j) += 2;
}
cout << lines[i] << endl;
}
Voila!
s[i] is a character in the string (actually, a character reference), not the string object itself. string::operator[] returns a char& in the docs. See here.
Consider declaring a std::vector<string> string_array; and then use the string_array.push_back(data) member function to append strings from the file onto the vector. Use a for loop to iterate through the vector at a later time with a vector<string>::iterator or the std::vector::size function to get the length of the vector for a traditional for loop (via a call to string_array.size()). Use the square brackets to get each string from the vector (string_array[0 or 1 or etc.]).
Get characters from each string in the vector by using something like string_array[n][m] for the mth character of the nth string. Iterating over each character should be as simple as using the string::length member function to get the string length, and then another for loop.
Also, std::cout << s << std::endl is being used in the wrong places. To output each character, try std::cout << s[i] << std::endl instead, or printf("%c", s[i]), whichever you like.
I'd suggest not using an array to hold strings from the file because you don't know what the array's length will be at runtime (the file size could be unbounded), so a vector is better suited for this case.
Finally, if you need code, there's a beginner's forum post here that I think will help you out. It has a lot of code like yours, but you'll have to modify it for your purposes.
Finally, please use:
std::someCPPLibraryFunction(args);
instead of...
using namespace std;
someCPPLibraryFunction(args);
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!
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.