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);
Related
At the end of the program I output the contents of a vector, the strings were inputted from a text file. The entire vector is outputted, but how do I just output one word? I am asking this because I will later need to modify each string.
#include<iostream>
#include<fstream>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
ifstream in;
string line, file_name;
vector <string> phrase;
int total_words, total_letters, total_chars;
cout << "PIG LATIN PROGRAM" << endl;
cout << "Which file are you accessing? : ";
cin >> file_name;
in.open(file_name);
if (in.fail()) cout << "\nFile not found!" << endl;
while(getline(in, line)) phrase.push_back(line);
for(int i = 0; i < phrase.size(); i++){
int limit = phrase.size() - 1;
while(i < limit && phrase[i] == phrase[i]){
i++;
}
cout << phrase[i];
}
You could start by splitting the line in phrase[i] at points there's whitespace:
std::istringstream iss{phrase[i]};
std::vector<std::string> words;
std::string word;
while (iss >> word)
words.push_back(std::move(word));
std::istringstream creates an input stream - a bit like cin - that contains the full line of text read from your file and stored in phrase[i]. If you then use >> word it will extract one whitespace-delimited word of text at a time.
Say your line/phrase[i] input contained "the blue socks were her favourites", it'll be split nicely into words. If there is also punctuation in the line, some of the strings in words will embed that punctuation, e.g. "world.". If you care about that, you can learn to use std::string member functions to search in and edit the strings.
In the case of punctuation you could use
std::erase(std::remove_if(word.begin(), word.end(), std::ispunct), word.end()) to remove it (further details/explanation).
phrase[i] == phrase[i]
Well, that's just redundant. This will always return true for a vector holding strings.
for(int i = 0; (...); i++){
while( (...) ){
i++;
}
}
You are modifying variable i twice in this a single for loop. Once in the third parameter of for, and once in an inner while loop. It's almost never a good idea.
What's happening here is that you set i=0, then immediately set it to point to the last element of a vector (as the second condition in while is always true).
Then you print this element to console, which is the last line of your text file.
What you want to do, is:
1. Load text file line by line into a vector.
2. Each element of vector will hold a single line.
3. Split each line into a vector of WORDS (space separated).
4. Work with the resulting vector.
Or pheraps:
1. Load file word by word at the beginning.
vector<string> words;
copy( istream_iterator<string>{YourFileStream}, istream_iterator<string>{}, back_inserter{words} ); // this will copy the content of file directly into vector, white-space-separated (no need for while loop to do it)
for ( auto i = phrase.begin(); i != phrase.end(); ++i ) // it's the proper c++ way of iterating over a vector. very similar, but variable i will point to every element of vector in order ( not just to the index of an element )
{
// do some work on *i. at least:
std::cout << *i; // dereference operator (*) is needed here, since i doesn't hold index of an element, it's a "pointer" to an element
}
If you need the first approach ( to differentiate between words in different lines ), here you can find some excellent ways to separate a string by any delimeter (space, for example): The most elegant way to iterate the words of a string
I have text file that is a large list of integers separated by commas.
E.g. "1,2,2,3,3,4,1,3,4,10".
Every two integers represents a vertex adjacency in a graph.
I want to create some C++ code that reads the text file and recognizes every two integers as some sort of data structure (such as a Boolean for yes/no adjacent).
Additionally I will be creating a class that colors this graph using these adjacencies. Being able to have the code remember what color or value each vertex has been given (this is not as important yet as just getting the program to parse in the data from the text file), but help with this would be appreciated or appear in a later question.
How would I do this in C++?
Assuming that the input file is one line comprised of a list of integers with a comma as the separator.
Seems like the mains steps are to:
Read in the the line as a string.
Parse the individual numbers out of the string (using ',' as the delimiter). So that each number is its own separate string.
Convert those individual strings to integers.
Once you have a vector of integers it should be pretty straightforward to get every pair and do as you wish.
Example:
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
using namespace std;
int main() {
fstream inFile;
inFile.open("input.txt"); // File with your numbers as input.
string tempString = "";
getline(inFile, tempString); // Read in the line from the file.
// If more than one line per file you can put this whole thing in a loop.
stringstream ss(tempString); // Convert from a string to a string stream.
vector<string> numbers_str = vector<string> (); // string vector to store the numbers as strings
vector<int> numbers = vector<int> (); // int vector to store the numbers once converted to int
while(ss.good()) // While you haven't reached the end.
{
getline(ss, tempString, ','); // Get the first number (as a string) with ',' as the delimiter.
numbers_str.push_back(tempString); // Add the number to the vector.
}
// Iterate through the vector of the string version of the numbers.
// Use stoi() to convert them from string to integers and add then to integer vector.
for(int i=0; i < numbers_str.size(); i++)
{
int tempInt = stoi(numbers_str[i], nullptr, 10); // Convert from string to base 10. C++11 feature: http://www.cplusplus.com/reference/string/stoi/
numbers.push_back(tempInt); // Add to the integer vector.
}
// Print out the numbers ... just to test and make sure that everything looks alright.
for(int i = 0; i < numbers.size(); i++)
{
cout << i+1 << ": " << numbers[i] << endl;
}
/*
Should be pretty straight forward from here.
You can go iterate through the vector and get every pair of integers and set those as the X and Y coor for your
custom data structure.
*/
inFile.close(); // Clean up. Close file.
cout << "The End" << endl;
return 0;
}
If your file has more than one line then you can just extend this and do the same thing for every line in your file.
Hope that helps.
I am 90% done with a homework project of mine but this last step is kicking my butt.
I have a text file that I'm going to be reading from for my program with commands on each line.
Most of the commands are a single letter, but one of them is a letter with an integer behind it.
I ideally need to read the line, if it's just a char go right into a function I've already written for the "Command". If it has a specific character, "F" in this case, I need it to also read the integer that will be separated by a space and pass that into my other function for that command.
Example;
.txt file;
R
L
L
F 20
R
R
For those who are curious I'm mimicking the function of the Logo language that used the little "turtle" to make logo animations for my homework.
Edit
I did try researching some methods to do this but most that I came up with either grabbed just the one char, or involved strings with which I could pull each "line" but then have to read and convert what was in string to separate char and int. If that is truly the "best" way to do it I'll suck it up and do it but I wanted to see if there was something that wasn't initially obvious to me.
This would be my approach:
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
int main() {
ifstream readFromFile("test.txt");
vector<string> fileWords;
string word;
while (readFromFile >> word) {
try {
int number = stoi(word); // here is your number
cout << number << endl;
} catch (const invalid_argument& exception) {
cout << exception.what() << endl; // just for debug
}
fileWords.emplace_back(word);
}
for (const auto& word: fileWords) {
cout << word << ' ';
}
readFromFile.close();
}
It reads word by word, saves it on an array and it also checks if a word is an integer (using the std::stoi function).
Solution by OP.
Resolved Kinda.
I ended up changing my fstream input to;
integer = 0;
char ch;
while(infile >> ch)
if (ch == "F")
{
infile >> integer;
}
// do stuff with code, I used a switch
Then after the switch I put I put integer back to 0.
This pulls the data I needed and stored it in the correct variables.
I have to create a program that will output various information about 1343 runners in a marathon. I'm having to import the data from a csv spreadsheet, so I chose to use the getline function. I use simple recursion to fill a string array and then simply use recursion once more to output the data. But for some reason, it only wants to display 300 or so runners' data. Here's the code:
int main(){
string data[1344];
vector<string> datav;
string header;
ifstream infile("C:\\Users\\Anthony\\Desktop\\cmarathon.csv");
int i = 0;
if (infile.is_open()) {
for (i=0; i<=1343; i++) {
getline(infile, data[i]);
}
datav.assign(data, data+1344);
for (int i = 0; i < datav.size(); i++) {
cout << datav[i] << "\n";
}
}
}
I attempted to use a vector in hopes it would help to allocate the required memory to execute the program properly (if that is in fact the problem here).
That code yields the perfect output of runners 1045-1343. I've tried simple work arounds, such as using several for() loops to combine the output seamlessly to no avail. Any information would be appreciated.
You do not need to copy from the array to the vector. You can add to the vector directly instead. Also, it is somewhat bad practice to shadow another local variable at the outer scope.
int main(){
string line;
vector<string> datav;
string header;
ifstream infile("C:\\Users\\Anthony\\Desktop\\cmarathon.csv");
if (infile.is_open()) {
// Are you supposed to read the header line first?
getline( infile, header );
while( getline( infile, line ).good() )
datav.push_back( line );
cout << "Container has " << datav.size() << " lines\n";
for (size_t i = 0; i < datav.size(); i++) {
cout << datav[i] << "\n";
}
}
}
Of course, you still have to break down each line to the individual fields, so pushing back a class or struct as EToreo suggested would be a good idea.
You should try using a struct to represent the fields in the CSV file and then make a vector of that struct type.
Now, loop through the file, reading each line till you reach the end of the file (Google how to do that) - DO NOT assume 1343, you don't have to. When you read in each line, create a new object from your struct and fill it with the content of that line (you will need to parse it by reading till a tab (\t) or the end of the string) and then datav.push(newObj) it onto your vector.
I suggest using the correct type's in your struct (int for age, string for name, etc.) and passing the string values from the file into those types. It will be much easier to do things like make a sum of everyone's age. You will thank yourself (and maybe me?) later.
If your not needing to use a vector:
for (i=0; i<=1343; i++) {
cout << data[i] << endl;
}
should work to print out whatever is in the data array
It is also possible to specify a delimeter for the getline function if you need to put different strings in different variables.
However EToreo's method may be more useful to you in the long run.
I've been trying to retrieve saved data from a text file. The data stored are both numbers, separated by a ~. I've managed to get it to print out one of the lines (the top line) however I've been unable to figure out how to proceed through the entire file.
There are only two numbers (integers) on each line, an X and Y position of another vector. The idea is to assign each integer to the respective variable in the vectors. I've not managed to get that far since I can't get it to go past line 1. But I'd thought that by having an array size of 2, and the array temporarily stores the value, assigns it to the vector, then overwrites it with the next value(s) that could work. But again not managed to get that far.
Below is the code I've been trying to use;
........
string loadZombieData;
loadFile >> loadZombieData; //Data gets read from the file and placed in the string
vector<string> result; //Stores result of each split value as a string
stringstream data(loadZombieData);
string line;
while(getline(data,line,'~'))
{
result.push_back(line);
}
for(int i = 0; i < result.size(); i++){
cout << result[i] << " ";
}
.......
Just to clarify, this is not my code, this is some code I found on Stackoverflow, so I'm not entirely certain how it all works yet. As I said, I've been trying to get it to read multiple lines, then using the for loop was going to assign the results to the other vector variables as needed. Any help is appreciated :)
Use two while loops:
std::vector<std::string> result;
std::vector<int> numbers;
std::string filename;
std::ifstream ifile(filename.c_str());
if (!ifile.is_open()) {
std::cerr << "Input file not opened! Something went wrong!" << std::endl;
exit(0);
}
std::string temp;
//loop over the file using newlines as your delimiter
while (std::getline(ifile, temp, '\n')) {
//now temp has the information of each line.
//create a stringstream initialized with this information:
std::istringstream iss(temp);//this contains the information of ONE line
//now loop over the string stream object as you would have in your code sample:
while(getline(iss, temp,'~'))
{
//at this point temp is the value of a token, but it is a string
result.push_back(temp); //note: this only stores the TOKENS as strings
//so to store the token as a int or float, you need to convert it to that
//via another stringstream:
std::istringstream ss(temp);
//if your number type is float, change it here as well as in the vector
//initialization of `numbers`:
int num = 0;
//this checks the stream to ensure that conversion occurred.
//if it did, store the number, otherwise, handle the error (quit - but, this is up to you)
//if stringstreams aren't your cup of tea, try some others (refer to this link):
//http://stackoverflow.com/questions/21807658/check-if-the-input-is-a-number-or-string-c/21807705#21807705
if (!(ss >> num).fail()) {
numbers.push_back(num);
}
else {
std::cerr << "There was a problem converting the string to an integer!" << std::endl;
}
}
}
Note: this version stores the numbers verbatim: i.e. without a sense of how many numbers were on a line. However, that is reconcilable as all you have to do is output n numbers per line. In your case, you know every 2 numbers will be represent the numbers in a line.
This requires:
#include <string>
#include <vector>
#include <cstdlib>
#include <sstream>