Searching words in a file with C++ language - c++

I'm editing my post with the progress I made so far. Well, what I want to do for now is:
Read the text file from the first line without asterics (*), aka the line beginning with number 1, to the end of the file
When there is a "blank space" instead of ">sa0" (6th column) put a # on the variable. And put the next string on the next variable (aka fsa1)
Print this to the user line by line.
The code I have so far:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
int main()
{
string line, netlist;
int address, fout, fin;
string name, type, fsa0, fsa1;
cout << "Wich Netlist you want to use?" << endl;
cin >> netlist;
ifstream file(netlist.c_str());
if (file.is_open())
{
do{
getline(file, line);
} while ( line[0] == '*' );
file >> address >> name >> type >> fout >> fin >> fsa0;
if (fsa0 != ">sa0") { fsa1 = fsa0; fsa0 = "#"; } else { file >> fsa1; }
cout << address << " " << name << " " << type << " " << fout << " " << fin << " " << fsa0 << " " << fsa1 << endl;
} else { cout << "File not found" << endl; }
file.close();
return 0;
}
Problems Found:
Not showing the first line after the last line with astherisc.
Not showing all the lines just the second one.
Text File im trying to read:
*c17 iscas example (to test conversion program only)
*---------------------------------------------------
*
*
* total number of lines in the netlist .............. 17
* simplistically reduced equivalent fault set size = 22
* lines from primary input gates ....... 5
* lines from primary output gates ....... 2
* lines from interior gate outputs ...... 4
* lines from ** 3 ** fanout stems ... 6
*
* avg_fanin = 2.00, max_fanin = 2
* avg_fanout = 2.00, max_fanout = 2
*
*
*
*
*
1 1gat inpt 1 0 >sa1
2 2gat inpt 1 0 >sa1
3 3gat inpt 2 0 >sa0 >sa1
8 8fan from 3gat >sa1
9 9fan from 3gat >sa1
6 6gat inpt 1 0 >sa1
7 7gat inpt 1 0 >sa1
10 10gat nand 1 2 >sa1
1 8
11 11gat nand 2 2 >sa0 >sa1
9 6
14 14fan from 11gat >sa1
15 15fan from 11gat >sa1
16 16gat nand 2 2 >sa0 >sa1
2 14
20 20fan from 16gat >sa1
21 21fan from 16gat >sa1
19 19gat nand 1 2 >sa1
15 7
22 22gat nand 0 2 >sa0 >sa1
10 20
23 23gat nand 0 2 >sa0 >sa1
21 19
And, another thing, can you guys give me some tips on what to do with these lines only with two integers, like the last one?
Thank you all. I appreciate all the help.

At least IMO, you're approaching this the wrong way. I'd start by reading a line of input. Then check how many items there are on that line. Then parse the items in the line appropriately.
Unless you're absolutely set on doing this in pure C++ on your own, something like AWK or yacc will make the job tremendously easier.
If you do insist on doing it without a parser generator or similar, you could at least use regular expressions to help out quite a bit.

Related

Reading each line from a text file, word by word and converting to int (Infinite loop or crashing?)

I'm trying to read in this text file:
8 4 4 6 1
8 4 4 6 2
8 4 4 6 3
8 4 4 6 4
8 4 4 6 5
8 4 4 6 6
8 4 4 6 7
8 4 4 6 8
11 4 4 6 3
15 11 13
7 2 1 4 4
9 4 3 9 9
8 2 1 5 4
10 1 2 3 4 6 1
6 1 1 2 5 3 2
13 1 1 2 10 3 8
11 2 11 10 7
And printing it exactly as shown to the console (to make sure I got every input).
However, for some reason my code crashes after reading in the first line. I can't even terminate the debugger.
Here's my code:
while(getline(inFile, buffer)){
buffer2 = strdup(buffer.c_str());
line = strtok(buffer2, " ");
size = atoi(line);
cout << size << " ";
while(line!=NULL){
line = strtok(NULL, " ");
cout << line << " ";
}
cout << "~~~~~~~~~" << endl;
}
If you are going to use C++ you should take advantage of that, use string streams:
#include <fstream>
#include <sstream>
#include <iostream>
using namespace std; //for sample purposes, should not be used
int main() {
int temp, count = 0, sum = 0, total = 0;
string buffer;
ifstream myFile("in.txt");
if (!myFile.is_open())
cout << "No file" << endl;
else{
while(getline(myFile, buffer)){
sum = 0;
stringstream ss(buffer);
while(ss >> temp){
count++; //number count
sum += temp; //line sum
cout << temp << " ";
}
total += sum; //total sum
cout << endl << "count: " << count << endl
<< "sum: " << sum << endl << "total: " << total << endl << endl;
}
myFile.close();
}
cout << "~~~~~~~~~" << endl;
}
You are leaking the memory allocated by strdup(). You need to call free() when you are done using buffer2.
But more importantly, strtok() returns NULL when there are no more tokens to return. But it is undefined behavior to pass a NULL char* pointer to operator<<. Your while loop is doing exactly that when it reaches the end of each line, so anything could happen, including crashing.
Try this instead:
while (getline(inFile, buffer)) {
buffer2 = strdup(buffer.c_str());
if (buffer2 != NULL) {
line = strtok(buffer2, " ");
while (line != NULL) {
size = atoi(line);
cout << size << " ";
line = strtok(NULL, " ");
}
free(buffer2);
}
cout << "~~~~~~~~~" << endl;
}
That being said, why are you using strdup(), strtok(), and atoi() at all? You are writing C++ code, you should C++ semantics instead of C semantics. For example, you can use std::istringstream instead, eg:
while (getline(inFile, buffer)) {
istringstream iss(buffer);
while (iss >> size) {
cout << size << " ";
}
cout << "~~~~~~~~~" << endl;
}
As always, there are many possible solutions. I would like to show an additional one. This is using more modern C++ elements, mainly from the algorithm and iterator library.
So, what will we do?
First we read each line as a std::string in a simple for loop with std::getline. Then we will put the line again in a std::istringstream so that we can take advantage of C++ iterator: std::istream_iterator.
This iterator will iterate over the elements in the string and extract all integers. It is like calling the extractor operator ( >> ) for all elements in the line string.
We use the iterator in the so called range constructor of os a std::vector. This inplace created vector, will be added to the destiantion data. So, as a result, we will get vector of vector of int: A 2-dimensional vector.
For debug purposes, we copy each row of intes to std::cout.
Please note that we do really need only very few and very simple statements to fulfill the task.
Please check.
#include <iostream>
#include <string>
#include <algorithm>
#include <sstream>
#include <vector>
#include <iterator>
std::istringstream sourceFile{R"(8 4 4 6 1
8 4 4 6 2
8 4 4 6 3
8 4 4 6 4
8 4 4 6 5
8 4 4 6 6
8 4 4 6 7
8 4 4 6 8
11 4 4 6 3
15 11 13
7 2 1 4 4
9 4 3 9 9
8 2 1 5 4
10 1 2 3 4 6 1
6 1 1 2 5 3 2
13 1 1 2 10 3 8
11 2 11 10 7)"};
int main()
{
// Here we will store the resulting int values
std::vector<std::vector<int>> data{};
for (std::string line{}; std::getline(sourceFile, line); ) {
// Split the line into integers and add to target array
std::istringstream iss(line);
data.emplace_back(std::vector<int>(std::istream_iterator<int>(iss), {}));
}
// Now all data is in our vector of vector of int
// Show read data on screen
std::for_each(data.begin(), data.end(), [](const std::vector<int>& v){
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " ")); std::cout << "\n";});
return 0;
}
Please note. I do not have files on SO. So I used a std::istringstream as input stream. You may of course exchange it with any other std::ftream

How to print the elements of a hockey stick in a pascal triangle in C++?

The starting row number and the length of the hockey stick will be taken as input. We need to print the elements of the hockey stick excluding the sum.
The following code prints the pascal triangle with 10 rows(row:0 to row:9). How to add code to get the elements of the hockey stick?
#include<iostream>
using namespace std;
int main()
{
int l, r, arr[10][10];
for (int i=0; i<=9; i++)
{
for(int j=0; j<=i; j++)
{
if((i==j)||(j==0))
{
arr[i][j] = 1;
cout << arr[i][j] << " ";
}
else
{
arr[i][j] = arr[i-1][j-1]+arr[i-1][j];
cout << arr[i][j] << " ";
}
}
cout << endl;
}
return 0;
}
It gives the output as below,
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1
Now we need to take starting row and length of hockey stick,
let's take
starting row-3
length-4
1
1 1
1 2 1
**1** 3 3 1
1 **4** 6 4 1
1 5 **10** 10 5 1
1 6 15 **20** 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1
sow hockey stick formation will be like,
1+4+10+20 = 35
We need to print the final output as below,
1+4+10+20
Note: No need to print the sum element-35
=================================
I have added the code as below,
cout <<"enter starting row-\n";
cin >> r;
cout << "enter length of hockey stick-\n";
cin >> l;
cout << "\nelements of hockey stick-\n";
int j=0;
for (int i=r; i<=(r+l-1); i++)
{
int j = i-r;
cout << arr[i][j] << " ";
}
cout << endl;
Got output as -
enter starting row-
3
enter length of hockey stick
4
elements of hockey stick-
1 4 10 20
But I need it to be as below.
1+4+10+20
The hint of HolyBlackCat is in general right...
...except that the last element would be suffixed by + as well.
That's why I would recommend to turn it around: prefix every element except the first with +. This is achieved with an initial separator string which is empty. It is overridden at end of loop:
const char *sep = "";
//int j=0; // unused
for (int i=r; i<=(r+l-1); i++)
{
int j = i-r;
cout << sep << arr[i][j];
sep = " + ";
}
cout << endl;
Note:
The assignment of sep in loop might be unnecessary for every than the first iteration. AFAIK, this is usually cheaper than an extra if test.

When converting a string array of numbers to an array of integers the elements are turned to 0s

When I convert info to integers and print out the array, the output is just 0s. Each element in info is a number entered as a string that was taken from a text file. For example: 513497628 19 4 16 4 7 14 18 15 10 6 6 1 7 17 88 10 79. I used strtok to remove the spaces from the line and enter the numbers into info. When I print out info all of the numbers are there. How do I get these to convert properly?
string info[1000]
int student[18];
for (int i=1; i<18; i++){
//cout << info[i] << endl;
stringstream convert(info[i]);
convert << student[n];
cout << student[n] << endl;
n++;
}
String Streams are my favorite tool for this. They automatically convert data types (most of the time) just like cin and cout do. Here is an example with a string stream. They are included in the library
string info = "513497628 19 4 16 4 7 14 18 15 10 6 6 1 7 17 88 10 79";
int student[18];
stringstream ss(info);
for (int i=0; i< 18; i++){
ss >> student[i];
cout << student[i] << endl;;
}
And here is a repl
https://repl.it/J5nQ

How to format this output C++

I've got a map containing a word and a set of integers as the value.
I want to output the word left aligned and then the integer values in the set in columns that are lined up. I thought that this would work but it seems to output very badly.
How would I go about adjusting this so that the number columns line up with one another and have a decent amount of spaces in between them?
for (auto cbegin = ident_map.begin(); cbegin != ident_map.end(); cbegin++) {
outFile << left << (*cbegin).first << setw(10);
for (set<int>::iterator setITR = (*cbegin).second.begin(); setITR != (*cbegin).second.end(); setITR++) {
outFile << right << *setITR << setw(4);
}
outFile << endl;
}
I think that this should output correctly but it comes out looking like this:
BinarySearchTree 4
Key 4 27
OrderedPair 1 4 8 14
T 4
erase 27
first 7 13
insert 1 4
key 27
kvpair 1 4
map_iterator 1 3 8 14
mitr 3 7 8 13 14
result 4 6 7 13
result2 8 9 14 15
second 6
t 4
value_type 1
Try Boost.Format
Here is a toy example that is similar in spirit to what you want to do. The %|30t| and %|50t| formatters ensure that your numbers are left-justified at the columns 30 and 50 respectively.
#include <iostream>
#include <boost/format.hpp>
int main(int argc, char *argv[]) {
std::cout << "0 1 2 3 4 5 " << std::endl;
std::cout << "012345678901234567890123456789012345678901234567890123456789" << std::endl;
for (int i = 0; i < 10; i++) {
// Set up the format to have 3 variables with vars 2 and 3 at
// columns 30 and 50 respectively.
boost::format fmt("string %1%: %|30t|%2% %|50t|%3%");
// Append values we want to print
fmt = fmt % i;
for (int j = 0; j < 2; j++) {
fmt = fmt % rand();
}
// Write to std::cout
std::cout << fmt << std::endl;
// Or save as a string...
std::string s = fmt.str();
}
return 0;
}
Which when run, produces:
$ ./a.out
0 1 2 3 4 5
012345678901234567890123456789012345678901234567890123456789
string 0: 16807 282475249
string 1: 1622650073 984943658
string 2: 1144108930 470211272
string 3: 101027544 1457850878
string 4: 1458777923 2007237709
string 5: 823564440 1115438165
string 6: 1784484492 74243042
string 7: 114807987 1137522503
string 8: 1441282327 16531729
string 9: 823378840 143542612
How about try using \t instead of setw(). \t is the tab special character. This will do wonders for your formatting as you can just figure out the number of tabs to your first position for each line, then it is as simple as following what format you would like, works great because tab is a uniform size

File stops being read after a newline character

I'm trying to create a spam filter. I need to train the model first. I read the words from a text file which has the word "spam" or "ham" as the first word of a paragraph, and then the words in the mail and number of its occurrences just after the word. There are paragraphs in the file. My program is able to read the first paragraph that is the words and their number of occurrences.
The problem is that, the file stops reading after encountering the newline that and doesn't read the next paragraph. Although I have a feeling that the way I am checking for a newline character that is the end of a paragraph is not entirely correct.
I have given two paragraphs so you just get the idea of the train text.
Train text file.
/000/003 ham need 1 fw 1 35 2 39 1 thanks 1 thread 2 40 1 copy 1 else 1 correlator 1 under 1 companies 1 25 1 he 2 26 2 168 1 29 2 content 4 1 1 6 1 5 1 4 1 review 2 we 1 john 3 17 1 use 1 15 1 20 1 classes 1 may 1 a 1 back 1 l 1 01 1 produced 1 i 1 yes 1 10 2 713 2 v6 1 p 1 original 2
/000/031 ham don 1 kim 5 dave 1 39 1 customer 1 38 2 thanks 1 over 1 thread 2 year 1 correlator 1 under 1 williams 1 mon 2 number 2 kitchen 1 168 1 29 1 content 4 3 2 2 6 system 2 1 2 7 1 6 1 5 2 4 1 9 1 each 1 8 1 view 2
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
int V = 0; // Total number of words
ifstream fin;
fin.open("train", ios::in);
string word;
int wordnum;
int N[2] = {0};
char c, skip;
for (int i = 0; i < 8; i++) fin >> skip; // There are 8 characters before the first word of the paragraph
while (!fin.fail())
{
fin >> word;
if (word == "spam") N[0]++;
else if (word == "ham") N[1]++;
else
{
V++;
fin >> wordnum;
}
int p = fin.tellg();
fin >> c; //To check for newline. If its there, we skip the first eight characters of the new paragraph because those characters aren't supposed to be read
if (c == '\n')
{
for (int i = 0; i < 8; i++) fin >> skip;
}
else fin.seekg(p);
}
cout << "\nSpam: " << N[0];
cout << "\nHam :" << N[1];
cout << "\nVocab: " << V;
fin.close();
return 0;
}
std::ifstream::operator>>() doesn't read \n in the variable; it drops it. If you need to manipulate with whitespaces and \n symbols, you can use std::ifstream::get()