How to read file with characters and integers c++ - c++

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.

Related

How to take multiple line string input in C++?

I am learning C++. I want to take multiple line string as input but I can't. I am using getline() for it but it is taking only one line input. When I press enter for writing next line it stoped taking input and print the first line.
I want to give input like the example below
Hello, I am Satyajit Roy.
I want to make a program.
I love to travel.
But it takes only the first line input.
My code:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s;
getline(cin, s);
cout << s << endl;
return 0;
}
Please help me to know how can I do that.
Thank you.
Either you write a loop to read individual lines and concatenate them to a single string, thats what this answer suggests. If you are fine with designating a specific character to signal the end of the input, you can use the getline overload that takes a delimiter as parameter:
#include <iostream>
#include <string>
int main() {
std::string s;
std::getline(std::cin,s,'x');
std::cout << s;
}
The user would have to type an x to end input, so this input
Hello, I am Satyajit Roy.
I want to make a program.
I love to travel.
x
would result in this output:
Hello, I am Satyajit Roy.
I want to make a program.
I love to travel.
Of course this won't work when the string to be entered contains x, which renders the approach rather useless.
However, instead of using a "real" character as delimiter you can use the EOF character (EOF = end of file) like this:
std::getline(std::cin, s, static_cast<char>(EOF));
Then input is terminated by whatever your terminal interprets as EOF, eg Ctrl-d in linux.
Thanks to #darcamo for enlightening me on the EOF part.
You can only read one line at a time with std::getline if you don’t provide your own delimiter. If you want to accumulate multiple lines, one at a time, you need a place to put the result. Define a second string. Read a line at a time into s with std::getline, and then append s to the result string. Like this:
std::string result;
std::string s;
while (std::getline(std::cin, s))
result += s;
You can take several lines using the code below if you know how many lines you will input.
int line=3, t;
string s, bigString;
for(int i=0 ; i<line ; i++)
{
getline(cin,s); // This is to input the sentence
bigString += s + "\n";
}
cout << bigString;
If you don't know how many lines you will input (Input from file until end of file) then you can check this.
string s;
vector<string> all;
while(getline(cin,s))
{
all.push_back(s);// This is to input the sentence
}
for(auto i:all)
{
cout << i << endl;
}

.size() string manipulation not reading actual length/size of characters c++

I am trying to read in an essay from a file which I then need to change each beginning letter of a sentence to an upper case letter and then send the corrected essay back to a file called correct.txt. The essay is stored in essay.txt.
So far I am just working with understanding the conversions from files to string in order for me to proceed with the rest of the question. So far, I have a string variable which which holds the essay with the words separated by a single space. I noticed that when I was trying to work with the size of my new string, it was not giving me the correct answer and I cannot figure out why. If you have any suggestions on how I can get it to notice the correct amount of characters, I would really appreciate it.
One more question while you're here, I know that moving forward, in order to change the beginning letters of the sentence to upper case, I need to first find the periods. Once I have this position, I can use pos+2 (including the preceding whitespace after the period) for the character that needs to become upper case. Is this the correct way of going about this and do you have any other tips on how to go forward with this?
Here is my code so far:
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
using namespace std;
int main(){
//declaring variables and creating objects
ifstream inputFile;
ofstream outputFile;
char inputFileName[20], outFileName[20];
cout << "Enter name of the file you want to open: " << endl;
cin >> inputFileName;
inputFile.open(inputFileName);
if (inputFile.fail()) {
cout << "Input file opening failed.\n";
exit(1);
}
cout << "Enter name of the file you want to send the output to: " << endl;
cin >> outFileName;
outputFile.open(outFileName);
if (outputFile.fail()) {
cout << "Output file opening failed.\n";
exit(1);
}
//while the file is open, it sends the contents to the string variable "essay"
string essay;
inputFile >> essay;
while (!inputFile.eof()) {
cout << essay << " ";
inputFile >> essay;
}
//this is to check for the correct size of the string "essay" before moving on to the rest of the code
int size = essay.size();
cout << size << endl;
return 0;
}
Your understanding of how the input stream works is incorrect.
The core of your code is this loop:
string essay;
inputFile >> essay;
while (!inputFile.eof()) {
cout << essay << " ";
inputFile >> essay;
}
What this does is that it reads the first word into essay, then, as long as the eof marker is not set on the stream it echoes back the word just read, and then reads another word, overwriting the previous one.
Here's the correct code. Note that checking for eof in a loop condition is a bad idea, because it doesn't quite do what you want, and would also get you stuck in an infinite loop if the stream instead entered an error condition.
string word;
while (inputFile >> word) { // read a word and stop if this fails for any reason
essay += word;
essay += " ";
}
Though I'm not sure why you read the file word by word instead of all at once.
Also, I feel the need to repeat what M.M. said in a comment: your use of raw character arrays on input is unsafe and unnecessary. Just use string. You need to then write inputFile.open(inputFileName.c_str()) unless your standard library is new enough to have the string overloads of these functions, but that is fine. The other way of doing it is dangerous and a very bad habit to get into.
Try include cstring on top of string as well.
String is considered char array which is a more 'unique' way of storing data. You can try the code listed below.
int size = essay.length();

Splitting sentences and placing in vector

I was given a code from my professor that takes multiple lines of input. I am currently changing the code for our current assignment and I came across an issue. The code is meant to take strings of input and separate them into sentences from periods and put those strings into a vector.
vector<string> words;
string getInput() {
string s = ""; // string to return
bool cont = true; // loop control.. continue is true
while (cont){ // while continue
string l; // string to hold a line
cin >> l; // get line
char lastChar = l.at(l.size()-1);
if(lastChar=='.') {
l = l.substr(0, l.size()-1);
if(l.size()>0){
words.push_back(s);
s = "";
}
}
if (lastChar==';') { // use ';' to stop input
l = l.substr(0, l.size()-1);
if (l.size()>0)
s = s + " " + l;
cont = false; // set loop control to stop
}
else
s = s + " " + l; // add line to string to return
// add a blank space to prevent
// making a new word from last
// word in string and first word
// in line
}
return s;
}
int main()
{
cout << "Input something: ";
string s = getInput();
cout << "Your input: " << s << "\n" << endl;
for(int i=0; i<words.size(); i++){
cout << words[i] << "\n";
}
}
The code puts strings into a vector but takes the last word of the sentence and attaches it to the next string and I cannot seem to understand why.
This line
s = s + " " + l;
will always execute, except for the end of input, even if the last character is '.'. You are most likely missing an else between the two if-s.
You have:
string l; // string to hold a line
cin >> l; // get line
The last line does not read a line unless the entire line has non-white space characters. To read a line of text, use:
std::getline(std::cin, l);
It's hard telling whether that is tripping your code up since you haven't posted any sample input.
I would at least consider doing this job somewhat differently. Right now, you're reading a word at a time, then putting the words back together until you get to a period.
One possible alternative would be to use std::getline to read input until you get to a period, and put the whole string into the vector at once. Code to do the job this way could look something like this:
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <iterator>
int main() {
std::vector<std::string> s;
std::string temp;
while (std::getline(std::cin, temp, '.'))
s.push_back(temp);
std::transform(s.begin(), s.end(),
std::ostream_iterator<std::string>(std::cout, ".\n"),
[](std::string const &s) { return s.substr(s.find_first_not_of(" \t\n")); });
}
This does behave differently in one circumstance--if you have a period somewhere other than at the end of a word, the original code will ignore that period (won't treat it as the end of a sentence) but this will. The obvious place this would make a difference would be if the input contained a number with a decimal point (e.g., 1.234), which this would break at the decimal point, so it would treat the 1 as the end of one sentence, and the 234 as the beginning of another. If, however, you don't need to deal with that type of input, this can simplify the code considerably.
If the sentences might contain decimal points, then I'd probably write the code more like this:
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <iterator>
class sentence {
std::string data;
public:
friend std::istream &operator>>(std::istream &is, sentence &s) {
std::string temp, word;
while (is >> word) {
temp += word + ' ';
if (word.back() == '.')
break;
}
s.data = temp;
return is;
}
operator std::string() const { return data; }
};
int main() {
std::copy(std::istream_iterator<sentence>(std::cin),
std::istream_iterator<sentence>(),
std::ostream_iterator<std::string>(std::cout, "\n"));
}
Although somewhat longer and more complex, at least to me it still seems (considerably) simpler than the code in the question. I guess it's different in one way--it detects the end of the input by...detecting the end of the input, rather than depending on the input to contain a special delimiter to mark the end of the input. If you're running it interactively, you'll typically need to use a special key combination to signal the end of input (e.g., Ctrl+D on Linux/Unix, or F6 on Windows).
In any case, it's probably worth considering a fundamental difference between this code and the code in the question: this defines a sentence as a type, where the original code just leaves everything as strings, and manipulates strings. This defines an operator>> for a sentence, that reads a sentence from a stream as we want it read. This gives us a type we can manipulate as an object. Since it's like a string in other ways, we provide a conversion to string so once you're done reading one from a stream, you can just treat it as a string. Having done that, we can (for example) use a standard algorithm to read sentences from standard input, and write them to standard output, with a new-line after each to separate them.

C++ - Xcode Program

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);

Why is cin.getline() skipping the first word in each line?

I am trying to display the text of a command line inputted text file line by line. But for some reason, it skips the first word in each line after the first line.
code:
using std::cout;
using std::cin;
using std::endl;
int main (int args, char* argv[])
{
char x[100];
char y[100];
char z[100];
cin.getline(x,100) >> argv[2];
cin.getline(y,100) >> argv[2];
cin.getline(z,100) >> argv[2];
cout << x <<endl;
cout << y <<endl;
cout << z <<endl;
return 1;
}
running ./a.out < moby.txt
displays this:
CHAPTER 1. Loomings.
me Ishmael. Some years ago--never mind how long precisely--having
or no money in my purse, and nothing particular to interest me on
but the first three lines in moby.txt is this:
CHAPTER 1. Loomings.
Call me Ishmael. Some years ago--never mind how long precisely--having
little or no money in my purse, and nothing particular to interest me on
The code is omitting "Call" and "little".
I feel like this is an \n error but i have no idea how to fix it.
Thanks in advance for any help.
cin.getline(x,100) >> argv[2];
You read a line (or the first 99 characters of the line) into x. Then you skip any whitespace and read the next word into argv[2]. The first words are ending up there.
Why are you using >> argv[2]? What are you possibly trying to do with this? argv[2] may not exist and even if it does, you don't have any control over the size of the character array pointed to by argv[2], so your chances of overrunning that array are quite high.
Rather than using char arrays directly for this, use std::getline with std::string to read lines into std::string objects: it is much easier to write correct code this way. For example,
std::string x;
if (!std::getline(std::cin, x)) {
// handle input error
}
#James McNellis has already pointed to the basic problem. My advice would be:
Don't use the member-function form of getline.
Don't mix getline and >> in the same statement.
Use a loop.
I find the other C++ getline to be easier and safer to use;
string str;
getline (cin,str);
will slurp the entire line and put it into a string, which you can then play with via the many fine string methods, or stringstream if you want to do I/O on parts of the string.
This is what I chose to do to make sure I am not missing any words or letters when I Use getline:
cout << "\nEnter some words: ";
while (getline(cin,myString)){
getline(cin,myString);
break;
};