Infile stops reading command line arguments - c++

**Edit: As it turns out, it was a simple typo under the if(i==0) statement. I missed putting {} to enclose both first_nonterminal statements.
I'm creating a CFG for an assignment, but I've gotten stuck. My program is supposed to read a file (of strings) by getting the file name from the command line, and then do certain things with the contents of the file.
using namespace std;
string current, first_nonterminal;
int main(int argc, char *argv[])
{
if(argc != 2)
{
std::cout << "No file name given" << std::endl; // if there is no file name in command line
exit(1);
}
ifstream infile(argv[1]);
if(!infile)
{
std::cout << "Given file " << argv[1] << " will not open."; // if file refuses to open
exit(2);
}
string word;
for(int i = 0; infile >> word; ++i)
{
cout << word << endl; // (debug) print input word
try // check if first word is in correct format
{
if (i == 0 && word.find(':') == string::npos) // check only first word,
{
throw runtime_error("File does not have correct format.");
}
}
catch(runtime_error &e)
{
cout << "Error:" << e.what();
exit(3);
}
if (i==0)
first_nonterminal = word;
first_nonterminal.pop_back(); // remove colon
insert(word); //put string through insert() method
}
randomize(); // randomize and replace
print(); // print end result
infile.close();
}
The above code intakes a file which is formatted like so:
STMT: THIS THAT OTHER
THIS: That carpet
THIS: Atlanta
THAT: is wild
OTHER: .
OTHER: , oooh OTHER2
OTHER2: oooh OTHER2
OTHER2: !
Any word that has a colon following it is considered a nonterminal, with the words following it considered terminals. Regardless, I've figured out the issue isn't my randomize() or insert() functions, as they work perfectly if I hard-code the file into the program. My issue is the file stops being read after a certain number of strings, and I'm not sure why. For example, when I put the above's file name into the command line, it runs through, but then after it puts "That" into the insert() function, it prints "carpet" via the debug cout, and then stops.

Related

I am getting several errors in this section of my code in which I am trying to turn the output into capital letters

{
const char* fname = "myfile"; //or string fname ("str.txt") in C++11
string input; //our first look at the C++ string object
fstream myfile; //construct fstream object for file i/o
openfile(myfile, fname, ios_base::out); //open file for output (current contents lost)
std::transform(myfile.open(), myfile.end(), myfile.open(), ::toupper);
while (cout << "Enter a line ('q' to quit): " && getline(cin, input))
{
if (input == "q")
break;
else //exit while loop
myfile << input << endl; //pipe string we read file add new line character
}
myfile.close(); //close our file
std::transform(myfile.open(), myfile.end(), myfile.open(), ::toupper);
openfile(myfile, fname, ios_base::in); //reopen it for input
cout << "\nHere's whats in " << fname << ":\n";
while (getline(myfile, input)) //get and print all the lines
cout << input << endl;
system("pause");
}
Severity Code Description Project File Line Suppression State
Error (active) E0304 no instance of overloaded function "std::basic_fstream<_Elem, _Traits>::open [with _Elem=char, _Traits=std::char_traits<char>]" matches the argument list fileio2 C:\Users\burnsk\source\repos\Hello\fileio2\fileio2.cpp 14
Severity Code Description Project File Line Suppression State
Error (active) E0109 expression preceding parentheses of apparent call must have (pointer-to-) function type fileio2 C:\Users\burnsk\source\repos\Hello\fileio2\fileio2.cpp 14
std::transform(myfile.open()
That's not going to work. std::transform expects an input iterator range, typically some begin/end range. std::fstream::open doesn't return an iterator.
You probably want to look at std::istream_iterator<char>.
We'll do a quick code review of what you've posted. I've removed most of your comments, and we'll actually use that as our first critique. The comments don't help readability at all. You're just restating the line of code, which isn't a great comment. Comments that explain 'why' or fill in the information gaps that the code alone cannot explain are much better.
// Missing includes and main()
// This does not qualify as a Minimal, Reproducible Example
// Specifically, it's not reproducible, as it cannot be copy/pasted
// and ran by the people you want to get help from.
// https://stackoverflow.com/help/minimal-reproducible-example
{
const char* fname = "myfile"; // Hard-coded file name is meh, C-string also
string input; // Prefer this EVERYWHERE
fstream myfile;
openfile(myfile, fname, ios_base::out); // No explanation of this function
// It's not standard, you should
// have posted its code.
// Bad syntax, as explained. Refer to the documentation
// https://en.cppreference.com/w/cpp/algorithm/transform
std::transform(myfile.open(), myfile.end(), myfile.open(), ::toupper);
// Clever, but the user likely doesn't need to be prompted before
// every line. Instead, you could have checked for the end condition.
while (cout << "Enter a line ('q' to quit): " && getline(cin, input))
{
if (input == "q")
break; // This is the line that exits the loop
else //exit while loop
myfile << input << endl; // Premature write
}
myfile.close();
// See above about transform syntax being bad. But why write data
// you don't want, close the file, re-open the file, try to
// re-write the data, and close the file again?
std::transform(myfile.open(), myfile.end(), myfile.open(), ::toupper);
openfile(myfile, fname, ios_base::in); //reopen it for input
cout << "\nHere's whats in " << fname << ":\n";
while (getline(myfile, input)) //get and print all the lines
cout << input << endl;
system("pause");
}
Since you are reading the strings in, and not caring about the original contents, why not manipulate the string to look the way you want, and then write it to the file. It's a lot simpler.
My code below does that, and uses a few other tricks to avoid copy/pasta.
The biggest change is that the user is only told what to do once, and the while() loop Boolean expression grabs the line and ensures it's not the quit condition.
The string is then run through std::transform() and fully capitalized. And then it is written to the file. This writes the data we want one time, instead of writing a bunch of bad data and then doubling back and trying to fix it.
For printing the contents of the file to the screen, we create a new class that holds a string and changes how it can be read in, essentially reading an entire line at a time instead of a word. This is not necessary, but like I said, I put some stuff in to avoid a straight copy/paste/submit situation.
#include <algorithm>
#include <cctype>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
namespace detail {
class Line {
std::string m_line;
public:
friend std::istream& operator>>(std::istream& sin, Line& line) {
std::getline(sin, line.m_line);
return sin;
}
operator std::string() const { return m_line; }
};
} // namespace detail
int main(int argc, char* argv[]) {
if (argc != 2) return 1;
std::ofstream fout(argv[1]);
if (!fout) {
std::cerr << "Error opening file for writing.\n";
return 2;
}
std::cout << "Type lines. Type \"q\" on its own line to quit.\n";
std::string line;
while (std::getline(std::cin, line) && line != "q") {
std::transform(line.begin(), line.end(), line.begin(),
[](const auto& c) { return std::toupper(c); });
fout << line << '\n';
}
fout.close();
std::ifstream fin(argv[1]);
if (!fin) {
std::cerr << "Error opening file for reading.\n";
return 3;
}
std::copy(std::istream_iterator<detail::Line>(fin),
std::istream_iterator<detail::Line>(),
std::ostream_iterator<std::string>(std::cout, "\n"));
fin.close();
}
Output:
❯ ./a.out text.txt
Type lines. Type "q" on its own line to quit.
You'll be back, time will tell
You'll remember that I served you well
Oceans rise, empires fall
We have seen each other through it all
And when push comes to shove
I will send a fully armed battalion to remind you of my love!
q
YOU'LL BE BACK, TIME WILL TELL
YOU'LL REMEMBER THAT I SERVED YOU WELL
OCEANS RISE, EMPIRES FALL
WE HAVE SEEN EACH OTHER THROUGH IT ALL
AND WHEN PUSH COMES TO SHOVE
I WILL SEND A FULLY ARMED BATTALION TO REMIND YOU OF MY LOVE!

Combining three text files into one text file forming a sentence C++

I am trying to create a program in C++ using Microsoft Visual Studio 2013. The main purpose of this program is to read three different files(headlines1,headlines2, and headlines3) and put them all together to form a single file and creating a sentence within that output file. I have figured out a function that I could use, but this function only reads and prints the 3 files out onto the console window. When I try to change the cout statement into an outfile, my outfile that I created is blank... I don't know what to do or how to structure the code.
#include<fstream>
#include<iostream>
#include<cstdlib>
using namespace std;
void readingFile(string[], ifstream &); //Funtion Prototype
int main()
{
string header1[50], header2[50], header3[50]; //Declaring array with 50 elements
int size1, size2, size3;
ifstream Fin, Fin2, Fin3;
ofstream Fout;
Fin.open("Headlines1.txt"); //Reading from these 3 files.
Fin2.open("Headlines2.txt");
Fin3.open("Headlines3.txt");
if (!Fin || !Fin2 || !Fin3) //Checking for unsuccessful open
{
cout << "Input file opening failed.\n";
cin.ignore();
return 1;
}
Fout.open("testingHeadlines.txt"); //Used for unsuccessful opening output
if (!Fout)
{
cout << "Output file opening failed.\n";
cin.ignore();
return 2;
}
cout << "Building.... Editing....\n" << endl;
cin.ignore();
cout << "Headlines file 1 below:\n" << endl;
readingFile(header1, Fin); //Function call
cout << endl << endl;
cout << "Headlines file 2 below:\n" << endl;
readingFile(header2, Fin2); //Function call
cout << endl << endl;
cout << "Headlines file 3 below:\n" << endl;
readingFile(header3, Fin3); //Function call
cout << endl << endl;
cin.ignore();
return 0;
}
//the function 'readingFile'
//Pre-conditions: Reads the contents from the files of Headlines1,2,and 3
//Post-conditions: Prints out the contents.
void readingFile(string[], ifstream &infile)
{
char next;
infile.get(next);
while (!infile.eof()) //Reading until EndOfFile
{
cout << next; //Problem is here?? I would think.
infile.get(next);
}
}
I'm just not certain if where I said the "Problem is here??" is where the problem is at. Every time I change the cout to outfile(I know, I have to change the parameters within the function header) once doing that I open the outfile and the file is blank.
All the files contain random words/phrases and when put together they will make a sentence. For ex. Headlines1 contains '***Queen Jennifer*'** Headlines2 contains '***has brain surgery*'** Headlines3 contains '***after eating 30 jalapenos.*'** and When put together it should read 'Queen Jennifer has brain surgery after eating 30 jalapenos.' but the files contain more words/ phrases that what I just listed in my example.
When I run the program above I am able to read all three Headline files, but they are printed in up to down form. For example, my output on my console screen would be:
Queen
Jennifer
has brain surgery
after eating 30 jalapenos
Problem:
Getting my headlines to read from left to right.
Getting them into a output file instead of the console screen.
Help Please.
You could replace this...
void readingFile(string[], ifstream &infile)
{
char next;
infile.get(next);
while (!infile.eof()) //Reading until EndOfFile
{
cout << next; //Problem is here?? I would think.
infile.get(next);
}
}
...and the calls there-to, such as...
readingFile(header1, Fin);
...with this...
void readingFile(ifstream& infile, ofstream& fout)
{
char next;
while (infile.get(next)) //Reading until EndOfFile or error
if (next != '\n') // if not newline
fout << next; // stream to file
}
...and calls ala...
readingFile(Fin, Fout);
That way readingFile is told where to write the output, and filters out the newline characters that were causing the output to appear on different lines.
This should do the trick.
#include <fstream>
#include <string>
int main() {
// Open the three files.
std::ifstream file_1("Headlines1.txt");
std::ifstream file_2("Headlines2.txt");
std::ifstream file_3("Headlines3.txt");
// Combine into one string.
std::string content;
content += std::string(std::istreambuf_iterator<char>(file_1),
std::istreambuf_iterator<char>());
content += std::string(std::istreambuf_iterator<char>(file_2),
std::istreambuf_iterator<char>());
content += std::string(std::istreambuf_iterator<char>(file_3),
std::istreambuf_iterator<char>());
// Output the string into a single file.
std::ofstream output_file("testingHeadlines.txt");
output_file << content;
}
I'm not sure what you're wanting to do about spacing between files, but that shouldn't be too hard for you to fine-tune this code for.
one possible thing why your ouput is like this is that std::ifstream::get() that you used in infile.get(next) is a non-formatted reading method which means it will not skip white spaces and newline character \n by default. so you need to check if next value is a newline like this:
if(next == '\n') continue ;
before passing it to cout << next. Thus you will skip printing a newline in your console screen.

Searching for a phrase in a text file c++

I'm trying to read a text file to find how many times a phrase/sentence(/substring?) occurs. I've done a real bodge job on it currently (see code below) but as you'll see, it relies on some rather clunky if statements.
I don't have access to the files I''ll be using it on at home, so I've used a file called big.txt and search for phrases like "and the" for the time being.
Ideally, I'd like to be able to search for "this error code 1" and it return the number of times it occurs. Any ideas on how I might get my code to work that way would be incredibly useful!
int fileSearch(string errorNameOne, string errorNameTwo, string textFile) {
string output; //variable that will store word from text file
ifstream inFile;
inFile.open(textFile); //open the selected text file
if (!inFile.is_open()) {
cerr << "The file cannot be opened";
exit(1);
}
if (inFile.is_open()) { //Check to make sure the file has opened correctly
while (!inFile.eof()) { //While the file is NOT at the end of the file
inFile >> output; //Send the data from the file to "output" as a string
if (output == errorNameOne) { //Check to look for first word of error code
marker = 1; //If this word is present, set a marker to 1
}
else if (marker == 1) { //If the marker is set to 1,
if (output == errorNameTwo) { //and if the word matches the second error code...
count++; //increse count
}
marker = 0; //either way, set marker to 0 again
}
}
}
inFile.close(); //Close the opened file
return count; //Function returns count of error
}
Given that your phrase can only occur once per line and the number follows the phrase after a number of spaces you can read the file line by line and use std::string::find() to see of your phrase is somewhere in the line. That will return the position of the phrase. You can then work on checking the rest of the line immediately after the phrase to test the number for 1 or 0.
This code may not be exactly what you want (still not certain of the exact specs) but hopefully it should contain enough examples of what you can do to achieve your goal.
// pass the open file stream in to this function along with the
// phrase you are looking for and the number to check
int count(std::istream& is, const std::string& phrase, const int value)
{
int count = 0;
std::string line;
while(std::getline(is, line)) // read the stream line by line
{
// check if the phrase appears somewhere in the line (pos)
std::string::size_type pos = line.find(phrase);
if(pos != std::string::npos) // phrase found pos = position of phrase beginning
{
// turn the part of the line after the phrase into an input-stream
std::istringstream iss(line.substr(pos + phrase.size()));
// attempt to read a number and check if the number is what we want
int v;
if(iss >> v && v == value)
++count;
}
}
return count;
}
int main()
{
const std::string file = "tmp.txt";
std::ifstream ifs(file);
if(!ifs.is_open())
{
std::cerr << "ERROR: Unable to open file: " << file << '\n';
return -1;
}
std::cout << "count: " << count(ifs, "Header Tangs Present", 1) << '\n';
}
Hope this helps.

Detect last line of file C++

I've been working on some code for a file parser function to learn some C++:
It's supposed to read in this text file:
>FirstSeq
AAAAAAAAAAAAAA
BBBBBBBBBBBBBB
>SecondSeq
TTTTTTTTTTTTTT
>ThirdSequence
CCCCCCCCCCCCCC
>FourthSequence
GGGGGGGGGGGGGG
and print out the names (lines with '>' at the start) and then the sequences.
However from the output:
AAAAAAAAAAAAAABBBBBBBBBBBBBB
TTTTTTTTTTTTTT
CCCCCCCCCCCCCC
FirstSeq
SecondSeq
ThirdSequence
FourthSequence
We see that the final line of G characters is not included. The code is below. What it does is loop over lines, if it finds a name, appends it to the vector of names, if it finds a sequence, appends it to a temporary string (incase the sequence is more than one line, like the first sequence), then when it finds the name of the next sequence, stores the built up temporary string in a vector and then proceeds by overwriting the temporary string and starting again. I suspect that it is because in the while loop of the function: The line fullSequence.push_back(currentSeq); which is called whenever a new name was detected previously to push the old temp string onto the vector would not be called for the last line of G's and so it is not being included, although the name "FourthSeq" is recorded, rather the line of G's is read into the temporary string, but then is not passed to the vector. So, how can I make it so as I can detect that this is the last line of the file and so should make sure the temporary string is pushed onto the vector?
Thanks,
Ben.
CODE:
#include<fstream>
#include<iostream>
#include<string>
#include<vector>
void fastaRead(string fileName)
{
ifstream inputFile;
inputFile.open(fileName);
if (inputFile.is_open()) {
vector<string> fullSequence, sequenceNames;
string currentSeq;
string line;
bool newseq = false;
bool firstseq = true;
cout << "Reading Sequence" << endl;
while (getline(inputFile, line))
{
if (line[0] == '>') {
sequenceNames.push_back(line.substr(1,line.size()));
newseq = true;
} else {
if (newseq == true) {
if(firstseq == false){
fullSequence.push_back(currentSeq);
} else {
firstseq = false;
}
currentSeq = line;
newseq = false;
} else {
currentSeq.append(line);
}
}
}
//Report back the sequences and the sequence names...
for ( vector<string>::iterator i = fullSequence.begin(); i != fullSequence.end(); i++) {
cout << *i << endl;
}
for ( vector<string>::iterator i = sequenceNames.begin(); i != sequenceNames.end(); i++) {
cout << *i << endl;
}
cout << fullSequence.size() << endl;
cout << sequenceNames.size() << endl;
inputFile.close();
} else {
perror("error whilst reading this file");
}
if(inputFile.bad()){
perror("error whilst reading this file");
}
}
int main()
{
cout << "Fasta Sequence Filepath" << endl;
string input = "boop.txt";
fastaRead(input);
return 0;
}
Getline() will "fail" when it finds an EOF in the line, so the last line you read will not go through your loop.
I've solved this problem two ways, either by having two flags or just by processing the last line after the loop.
For two flags, the loop requires both to be true, you set one to false when getline() fails, and you set the other one to false if the first one is false, this gives you one extra loop after EOF.
Good luck!

While Loop contines forever to get end of input string

How do I run the while loop until the end of line or null character reached.
Here is my code
#include<iostream>
using namespace std;
main()
{
char input[20];
cout<<"Enter a line: ";
cin>>input;
while(input!='\0')
{
cout<<"This is a text";
}
system("pause");
}
If you want to read until either a newline or a NUL, read one character at a time inside the loop.
#include<iostream>
int main()
{
char input;
std::cout << "Enter a line: " << std::flush;
while(std::cin >> input && input != '\n' && input != 0) {
std::cout << "This is a test\n";
}
}
Notes:
main requires a return type
Never, ever, say "using namespace std;"
Don't forget to flush if you want cout to appear immediately.
Notice the compound test in the while condition:
First, did the read succeed?
Next, is it not '\n' (one of your conditions).
Next, is it not NUL (the other of your conditions).
The body of the loop will be executed once per input character -- is that what you wanted?
But, consider if you have correctly specified your requirement. It is an unusual requirement -- why would there be a NUL in a text file, and why would you want to process each character individually?
In idiomatic C++, you can read the input file in a line at a time using std::getline:
std::string myString;
while(std::getline(std::cin, myString)) {
// process myString
}
If you just want to read in a single line:
std::string myString;
if(std::getline(std::cin, myString)) {
// process myString
}
Finally, if you want to read a line, and ignore its contents:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
try something like:
i = 0;
while ((input[i] != '\0') && i < 20)
{
cout<<"This is a text";
i++;
}
Like this:
std::string line;
if (std::getline(std::cin, line))
{
std::cout << "Thank you, you said, \"" << line << "\".\n";
}
else
{
// error, e.g. EOF
}
If you want to read multiple lines, use a while loop instead:
while (std::getline(std::cin, line))
{
std::cout << "Thank you, you said, \"" << line << "\".\n";
}
The issue is that you're reading an entire chunk of text at once and then printing it until the input is '\0'. However, you're never actually updating this inside the loop. You can either use cin inside the loop to get the input, OR if you're trying to output each character, you can index the char array.