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!
Related
**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.
Given a method that I wrote on my own, a text file is given and I want to save the items into a vector<Object> referenceObject. It works nearly, but if I got in my text file objects like, for example: " Book of light ", it just saves "Book", so it stops reading on the first space.
I read some other StackOverflow questions like mine, but for my problem they don't work.
Question: It returns all objects of my text file, except for my first object. So my list starts by index=1 and not by index=0. Why?
void openfile() {
ifstream inFile;
inFile.open("textfile");
if (inFile.fail()) {
cerr << "error open this file" << endl;
exit(1);
}
string item;
int count = 0;
vector<Object> referenceObject;
while (!inFile.eof()) {
while (getline(inFile, item)) {
inFile >> item;
Object s;
s.setName(item);
referenceCards.push_back(s);
std::cout << count << ' ' << referenceObject.at(count).getName() << endl;
count++;
}
}
When you do this:
while (getline(inFile, item)) { // reads line into item
inFile >> item; // overwrites item
// ... // do stuff with item
}
You are reading the first line, and then immediately ignoring it (by overwriting it with the first string up to the space from the second line).
Instead, simply do this:
while (getline(inFile, item)) { // read line into item
// ... // do stuff with item
}
Also, avoid this check:
while (!inFile.eof())
See Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong? for why it's recommended against.
So I'm having trouble grabbing a word from document1 and comparing it to the list of words in document2. So when I run the program, the first word of document1 is comparing to the list of words of document2, but the next word in document1 isn't comparing to the list in document2. I'm not sure what the problem is... Does it have something to do with the .eof() function?
string typedString, actualString, document1 = "A.txt", document2 = "Dictionary.txt";
ifstream observeDoc, actualDoc;
observeDoc.open(document1);
actualDoc.open(document2);
while (observeDoc.is_open())
{
while (true)
{
observeDoc >> typedString;
if (observeDoc.eof()) break;
cout << typedString << endl;
while (true)
{
actualDoc >> actualString;
if (actualDoc.eof())
{
actualDoc.open(document1);
break;
}
cout << '\t' << actualString << endl;
}
}
if (observeDoc.eof()) break;
}
observeDoc.close();
actualDoc.close();
OUTPUT:
You need to go back to the beginning of the file.
you can use: observeDoc.seekg(0,ios::beg);
A better solution is to read all the words of the 1st file to an object from type std::set<std::string>, and for each word in the 2nd file check for existence in the set. In this way you move just once on each file, and no need to rewind.
std::set<std::string> words;
observeDoc.open(document1);
while (observeDoc >> typedString){
words.insert(typedString);
}
observeDoc.close();
actualDoc.open(document2);
while(actualDoc >> actualString){
if (words.find( actualString )!= words.end()){
//word exists in observer doc!
}
}
actualDoc.close();
Your problem is that actualDoc isn't resetting properly at the end of your loops. Also, your loop syntax could be way cleaner. Try this:
string typedString, actualString, document1 = "A.txt", document2 = "Dictionary.txt";
ifstream observeDoc, actualDoc;
observeDoc.open(document1);
actualDoc.open(document2);
// Will stop when it reads in EOF
while (observeDoc >> typedString)
{
while (actualDoc >> actualString)
{
// Do your comparisons here
}
actualDoc.open(document2); //reset actualDoc to start from the beginning of the file
// or, as #SHR recommended, use observeDoc.seekg(0,ios::beg);
}
observeDoc.close();
actualDoc.close();
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.
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.