Checking stringstream line char by char C++ - c++

I will keep it short and simple. After making sure that user is able to open a file succesfully, I have written the following piece of code to take a line from the inputFile.
string line;
int counter = 0;
DynIntStack stack;
while (!inputFile.eof())
{
getline(inputFile, line);
stringstream inputLine(line);
counter++;
//I NEED TO DO IT HERE
}
This will be used to write program to check balanced paranthesis in an input cpp file and I have to use stacks. Classic CS homework as I understand from the topics I have checked :)
counter is updated after every line and the line number(counter) is to be pushed to the stack if it has a opening bracket and it must be popped from the stack if it is a closing bracket. after these, the output should look something like this:
block: 3 - 3
block: 12 - 14
block: 10 - 14
block: 5 - 16
Syntax error in line 21.
But I do not know how to check the line I got char by char. I need a loop to check the chars and apply the previously mentioned things if an opening or closing bracket is found. How can I check the line char by char.
using any data container other than stacks is forbidden.
thank you very much :)

But I do not know how to check the line I got char by char
Is this what you want?
string line;
int counter = 0;
DynIntStack stack;
while (getline(inputFile, line))
{
counter++;
for(size_t i = 0; i < line.length(); i++) {
// line[i] is i'th character
if(line[i] == '(') {
// do stuff
}
else if(line[i] == ')') {
// do stuff
}
}
}

In addition to the correct answer by Kaidul Islam, a std::string support range based for loops.
string line;
int counter = 0;
DynIntStack stack;
while (getline(inputFile, line))
{
++counter;
for (char const c : line)
{
if (c == '(')
{
// do stuff
}
else if (c == ')')
{
// do stuff
}
}
}

Related

Counting instances of a character in select lines

Currently learning c++ and I'm pretty stumped. I want to count the instances of a character in a text file - but not including lines that start with a certain character. Specifically, I'm counting instances of Gs and Cs in a text file, but not including lines that begin with "*"
Example
*metadata information
atgctaatgcaggtcagtcagtcagtcatgcg
atgcagtcagtcactgactgactgactgaata
*metadata information
atgtagcagctagtcagtcagtcagcatatat
gatcgactagctgactgacgtactgactgaat
char Z;
long GC=0;
string Line;
while(getline(InFile, Line))
{
if(Line[0]=='*')
{
InFile.get(Z);
while(InFile.get(Z))
{
if(Z=='G' || Z=='C' || Z=='g' || Z=='c')
{
++GC;
}
}
}
}
I'm able to count the instances of g and c across the entire text, but just haven't been able to limit the function to lines that do not begin in >
My understanding of your requirements, you want to ignore lines starting with '*'.
while (getline(InFile, Line))
{
if (Line[0] == '*')
{
continue; // ignore the line
}
for (int i = 0; i < Line.length(); ++i)
{
const char c = std::toupper(Line[i]);
if ((c == 'G') || (c == 'C`))
{
++GC;
}
}
}
In the above code, if the first line character is '*', the line is ignored.
Otherwise, the string is searched for 'G' or 'C' characters.
InFile.get(Z);
while(InFile.get(Z))
You don't want those lines. At this point in your code, the whole string has already been read in string Line;
You probably want
for(auto c: Line) // go over every char in Line
{
And you probably want to fix:
if(Line[0] != '*')
because
but not including lines that start with a certain character.

Matching word c++ program using getline() running infinitely?

I am learning c++ so bear with me and apologize for any idiocy beforehand.
I am trying to write some code that matches the first word on each line in a file called "command.txt" to either "num_lines", "num_words", or "num_chars".
If the first word of the first line does not match the previously mentioned words, it reads the next line.
Once it hits a matching word (first words only!) it prints out the matching word.
Here is all of my code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
ifstream comm_in("commands.txt"); // opens file
string command_name = "hi"; // stores command from file
bool is_command() {
if (command_name == "num_words" || command_name == "num_chars" || command_name == "num_lines") {
return true;
} else {
return false;
}
}
// FIND a first word of a line in file THAT MATCHES "num_words", "num_chars" or "num_lines"
void get_command() {
string line;
char c;
while (!is_command()) { // if command_name does not match a command
// GET NEXT LINE OF FILE TO STRING
getline(comm_in, line);
// SUPPOSED TO GET THE FIRST WORD OF A STRING (CANT USE SSTREAM)
for (int i = 0; i < line.size(); i++) { // increment through line
c = line[i]; // assign c as index value of line
if (c == ' ' || c == '\t') { // if c is a space/tab
break; // end for loop
} else {
command_name += c; // concatenate c to command_name
} // if
} // for
} // while
return;
}
int main() {
get_command();
cout << command_name; // supposed to print "num_lines"
}
The contents of the command.txt file:
my bear is happy
and that it
great ha
num_lines sigh
It compiles properly, but when I run it in my terminal, nothing shows up; it doesn't seem to ever stop loading.
How can I fix this?
Unless you really want to hate yourself in the morning (so to speak) you want to get out of the habit of using global variables. You'll also almost certainly find life easier if you break get_command into (at least) two functions, one specifically to get the first word from the string containing the line.
I'd write the code more like this:
bool is_cmd(std::string const &s) {
return s == "num_words" || s == "num_chars" || s == "num_lines";
}
std::string first_word(std::istream &is) {
std::string line, ret;
if (std::getline(is, line)) {
auto start = line.find_first_not_of(" \t");
auto end = line.find_first_of(" \t", start);
ret = line.substr(start, end - start);
}
return ret;
}
void get_command(std::istream &is) {
std::string cmd;
while (!(cmd = first_word(is)).empty())
if (is_cmd(cmd)) {
std::cout << cmd;
break;
}
}
This still isn't perfect (e.g., badly formed input could still cause it to fail) but at least it's a move in what I'd say is a better direction.
If something goes wrong and you reach the end of file the loop will never stop. You should change getline(comm_in, line) to if(!getline(comm_in, line)) break;, or better yet, use that as the condition for the loop.
You also have to reset command_name for each pass:
while(getline(comm_in, line))
{
command_name = "";
for(int i = 0; i < line.size(); i++)
{
c = line[i];
if(c == ' ' || c == '\t')
break;
else
command_name += c;
}
if(is_command())
break;
}
// FIND a first word of a line in file THAT MATCHES "num_words", "num_chars" or "num_lines"
void get_command()
{
string line;
char c;
while (!is_command()) { // if command_name does not match a command
// GET NEXT LINE OF FILE TO STRING
if(getline(comm_in, line),comm_in.fail()){
// end reading
break;
}
//clear
command_name = "";
// SUPPOSED TO GET THE FIRST WORD OF A STRING (CANT USE SSTREAM)
for (int i = 0; i < line.size(); i++) { // increment through line
c = line[i]; // assign c as index value of line
if (c == ' ' || c == '\t') { // if c is a space/tab
break; // end for loop
} else {
command_name += c; // concatenate c to command_name
} // if
} // for
} // while
return;
}
The key of this problem is that you didn't clear the command_name.
What's more, you have to add a judge about whether reaching the end of the file.
ps: if(getline(comm_in, line),comm_in.fail()) is equal to if(getline(comm_in, line)),

Txt to 2 different arrays c++

I have a txt file with a lot of things in it.
The lines have this pattern: 6 spaces then 1 int, 1 space, then a string.
Also, the 1st line has the amount of lines that the txt has.
I want to put the integers in an array of ints and the string on an array of strings.
I can read it and put it into an array , but only if I'm considering the ints as chars and putting into one array of strings.When I try to separate things I have no idea on how I'd do it. Any ideas?
The code I used for putting everything in an array was this:
int size()
{
ifstream sizeX;
int x;
sizeX.open("cities.txt");
sizeX>>x;
return x;
};
int main(void)
{
int size = size();
string words[size];
ifstream file("cities.txt");
file.ignore(100000,'\n');
if(file.is_open())
{
for(int i=0; i<size; i++)
{
getline(file,words[i]);
}
}
}
Just to start I'm going to provide some tips about your code:
int size = size();
Why do you need to open the file, read the first line and then close it? That process can be done opening the file just once.
The code string words[size]; is absolutely not legal C++. You cannot instantiate a variable-length-array in C++. That C feature has been not included in C++ standard (some ref). I suggest you to replace with std::vector, which is more C++ code.
Here I write a snippet of function which perform what you need.
int parse_file(const std::string& filename,
std::vector<std::string>* out_strings,
std::vector<int>* out_integers) {
assert(out_strings != nullptr);
assert(out_integers != nullptr);
std::ifstream file;
file.open(filename, std::ios_base::in);
if (file.fail()) {
// handle the error
return -1;
}
// Local variables
int num_rows;
std::string line;
// parse the first line
std::getline(file, line);
if (line.size() == 0) {
// file empty, handle the error
return -1;
}
num_rows = std::stoi(line);
// reserve memory
out_strings->clear();
out_strings->reserve(num_rows);
out_integers->clear();
out_integers->reserve(num_rows);
for (int row = 0; row < num_rows; ++row) {
// read the line
std::getline(file, line);
if (line.size() == 0) {
// unexpected end of line, handle it
return -1;
}
// get the integer
out_integers->push_back(
std::stoi(line.substr(6, line.find(' ', 6) - 6)));
// get the string
out_strings->push_back(
line.substr(line.find(' ', 6) + 1, std::string::npos));
}
file.close();
return 0;
}
You can definitely improved it, but I think it's a good point where to start.
The last suggest I can give you, in order to improve the robustness of your code, you can match each line with a regular expression. In this way you can be sure your line is formatted exactly how you need.
For example:
std::regex line_pattern("\\s{6}[0-9]+\\s[^\\n]+");
if (std::regex_match(line, line_pattern) == false) {
// ups... the line is not formatted how you need
// this is an error
}

C++, reading chars into a vector<char> from a file, character by character

I am trying to read in the first 7 chars of a file named "board.txt" into a vector<'char> but I am having issues for some reason. I am not too familiar with C++ so any advice would be appreciated, here is the code I have so far
//rack
int charCount = 0;
char ch;
ifstream rackIn("board.txt");
while(rackIn.get(ch) && charCount < 7){
this->getMyRack().push_back(ch);
}
And here is the function getMyRack used in the code above:
vector<char> board::getMyRack(){
return this->myRack;
}
myRack is a char vector
I tried to test this in my main using this:
for (int i = 0; i < test->getMyRack().size(); ++i){
cout << test->getMyRack().at(i);
}
but it does not output anything, why are the chars i am reading in not being added into my char vectors?
Because you don't put char in your vector. Your function getMyRack() returns vector but not address of your vector. You can add method to your class board for adding char, for example:
void board::addChar(char c){
this->myRack.push_back(c);
}
And then call this function:
while(rackIn.get(ch) && charCount < 7){
this->addChar(ch);
}
Or change the return type of your function.
read line one or (how much lines required) from file to a string
create substring of 7 chars from beginning
std::ifstream file("board.txt");
std::string str;
// to read single line
std::getline(file, str);
// to read 7 chars
str= str.substr(0,7);
vector<char> char_buf;
for(size_t i =0; i <= str.size();i++)
{
char_buf.push_back(str[i])
}
// use the char_buf
easier or second way is use
#include<fstream> // for ifstream
#include <cstdlib> // for exit()
std::string file_name ="board.txt";
std::ifstream input_stream;
std::vector<char> char_buf;
input_stream.open(file_name);
if(input_stream.fail()) { exit(0);}
int char_no=0;
while(i<=7)
{
char c = input_stream.get();
char_buf.push_back(c);
i++;
}
// use char_buf
std::string str;
int char_count=0;
// Read the next line from File untill it reaches the 7.
while (std::getline(in, str)&& char_count!=7)
{
// Line contains string of length > 0 then save it in vector
if (str.size() > 0)
your_char_vector.push_back(str);
char_count++;
if(char_count==7)
break;
}

Reading text file per line in C++, with unknown line length

I have a text file, that is formatted somewhat like this:
1 3 4 5 6
6 7 8
4 12 16 17 18 19 20
20
0
A line can contain 1 to 10000 integers. What I need to do, is read all of them line by line.
Pseudocode like this:
line=0;
i=0;
while(!file.eof()){
while(!endLine){
array[0][i++]=file.readChar();
}
line++;i=0;
}
So, I have an array , into which I would like to read every line, and each line would consist of each of these integers.
The problem I'm having, is how to check if the end of a line has come.
Note, I can't use strings.
Yes, This is for a homework, but the main task for the assignment is to build a tree and then transform it. I can do that, but I've no idea how to read the integers from the file.
Probably something like this:
after reading an int, I manually skip spaces, tabs, carriage return and end of line (for this one you'll have to implement your logic).
To read an int I read it directly using the C++ functions of ifstream. I don't read it character by character and then recompose it as a string :-)
Note that I skip \r as "spaces. The end of line for me is \n.
#include <iostream>
#include <fstream>
#include <vector>
int main()
{
std::ifstream file("example.txt");
std::vector<std::vector<int>> ints;
bool insertNewLine = true;
int oneInt;
//The good() here is used to check the status of
//the opening of file and for the failures of
//peek() and read() (used later to skip characters).
while (file.good() && file >> oneInt)
{
if (insertNewLine)
{
std::vector<int> vc;
ints.push_back(vc);
//With C++11 you can do this instead of the push_back
//ints.emplace_back(std::vector<int>());
insertNewLine = false;
}
ints.back().push_back(oneInt);
std::cout << oneInt << " ";
int ch;
while ((ch = file.peek()) != std::char_traits<char>::eof())
{
if (ch == ' '|| ch == '\t' || ch == '\r' || ch == '\n')
{
char ch2;
if (!file.read(&ch2, 1))
{
break;
}
if (ch == '\n' && !insertNewLine)
{
std::cout << std::endl;
insertNewLine = true;
}
}
else
{
break;
}
}
}
//Here we should probably check if we exited for eof (good)
//or for other file errors (bad! bad! bad!)
return 0;
}
There is a function called getline() which will read a whole line. Link
You need a function to read a value from a file or indicates an end of line or end of file condition, something like:
result_type GetNextValue (input_file, &value)
{
if next thing in file is a number, set value and return number_type
if next thing in file is an end of line, return end_of_line_type
if end of file found, return end_of_file_type
}
and then your array building loop becomes:
line = 0
item = 0
eof = false
while (!eof)
{
switch (GetNextValue (input_file, value))
{
case value_type:
array [line][item++] = value
case end_of_line_type:
line++;
item = 0;
case end_of_file_type:
eof = true
}
}
I'll leave the details to you as it's homework.
You could read the numbers in a char and check against carriage return. A snippet that I had just tried is given below:
ifstream ifile;
ifile.open("a.txt");
char ch;
while((ch = ifile.get()) != EOF)
{
std::cout<<ch<<"\n";
if (ch == '\n')
std::cout<<"Got New Line";
}
ifile.close();