Assume that we are given input file in the following form:
12 a -5
T 23 -1 34 R K s 3 4 r
a a 34 12 -12 y
Now, we need to read the entire file and print the following:
number of integers
number of lowercase char
number of uppercase char
sum of all integers
Questions like this have always been a thorn in my flesh and I want to get this over with once and for all.
You need to parse the file:
1) separate raw text into tokens, then
2) "decide" if the token is a string, an integer, or "something else".
3) Count the results (#/integers, #/strings, etc)
Here's an example: Parse A Text File In C++
Here's the canonical textbook on the subject: The Dragon Book
Basically you want to parse the command line, open the file, parse each line token by token, and check the requirements for each token. I hope this helps.
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <stdlib.h>
using namespace std;
int main(int argc, char* argv[]) {
ifstream in(argv[1]);
string line, ch;
int int_count = 0, upper_count = 0, lower_count = 0, sum = 0;
/* Grab each line from file and place contents into line */
while(getline(in, line)) {
istringstream ss(line);
/* Parse each token in line */
while(ss >> ch) {
/* Is it a digit? */
if(isdigit(ch[0])) {
int_count++;
sum += atoi(ch.c_str());
}
/* If it's not, then it must be a char */
else {
if(isupper(ch[0]))
upper_count++;
else
lower_count++;
}
}
}
in.close();
cout << "Number of integers: " << int_count << endl;
cout << "Number of lowercase char: " << lower_count << endl;
cout << "Number of uppercase char: " << upper_count << endl;
cout << "Sum of all integers: " << sum << endl;
return 0;
}
Split by space
Check that it contains only 0-9, '-' and '.', if it does, it's probably a number. If it doesn't; probably some text.
Tally up as you go along.
Related
#include <iostream> // to generate the hexadecimal representation of a number
#include<string>
using std::string;
int main()
{
const string hexdigits("0123456789ABCDEF"); //possible hexdigits
std::cout << "enter the series of numbers between 0 and 15"
<< "separated by space. Hit enter when finished: "
<< std::endl; //line to be printed on screen
string result; // it will hold hexadecimal representation of the number
string::size_type n; // undefined string variable will hold numbers
while (std::cin >> n) // input number with just spaces
{
if (n < hexdigits.size()) // compares n with hexdigits size
{
result += hexdigits[n]; // storing string output in result
}
}
std::cout << "your hex number is: " << result << std::endl; //output result
return 0;
}
when I press ENTER after input, the output hex is not automatically generated. I have to use escape sequence \n after input, to proceed to output. how can I get my output with just hitting ENTER after give input numbers?
I tried using getline to get the whole line and exit, as given below
while(std::getline(std::cin, n))
but it gave error E0304
no instance for overloaded function 'std::getline' matches the argument list".
You need to provide a std::string argument to getline. The conversion is not correct either in several ways, but there are a lot of examples that show how to convert a hex string to a number. For example:
#include <iostream>
#include <string>
#include "stdlib.h"
int main()
{
std::string line;
if (std::getline(std::cin, line))
{
unsigned int value = strtoul(line.c_str(), NULL, 16);
std::cout << "your hex number is: " << value << std::endl; //output result
}
return 0;
}
You're a bit confused about types and logic. Firstly while(std::getline(std::cin, n)) does not work because n is not a string, getline only works with strings. Secondly even if getline worked with numbers the logic would not be correct because you want to input a single line but a while loop with getline would input multiple lines.
The answer is to use getline once to input a single line and then use a while loop to convert each of the numbers in the single line. To do this you have to know how to read numbers from a string (instead of from the console). I guess this is the part you are missing.
Here's some sample code (untested)
#include <iostream>
#include <sstream>
#include <string>
int main()
{
const std::string hexdigits("0123456789ABCDEF"); //possible hexdigits
std::cout << "enter the series of numbers between 0 and 15"
<< "separated by space. Hit enter when finished: "
<< std::endl;
std::string line;
if (getline(std::cin, line)) // read a line
{
std::istringstream buf(line);
unsigned result = 0, n;
while (buf >> n) // read numbers from the line
{
if (n < hexdigits.size())
{
result += hexdigits[n];
}
}
std::cout << "your hex number is: " << result << std::endl;
}
return 0;
}
BTW try to avoid commenting the obvious, comments like // compares n with hexdigits size add nothing to your code.
The 'program' is to take input in then spit the string back out on seperate lines and all numbers are to be multiplied by two in this case.
My issue occurs when a number is input after a white space.
Example
Sentence: 12 fish
Outputs:
24
fish
But...
Sentence: there are 12
Outputs:
there
are
0
The program I have written:
#include <iostream>
#include <string>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
using namespace std;
int main()
{
string str;
int number = 811;
cout << "Sentence: ";
getline(cin,str);
istringstream iss(str);
while(iss)
{
bool ree = 0;
string word;
iss >> word;
if(isdigit(word[0]))
{
stringstream(str) >> number;
number = (number * 2);
cout << number << endl;
ree = 1;
number = 911;
}
if(!ree)
{
cout << word << endl;
}
ree = 0;
}
}
Hopefully it's something small I am not seeing!
Thanks for the help in advanced.
The problem is that
stringstream(str) >> number;
creates a fresh string stream from the initial sentence, then tries to extract from it into number. Of course that will fail (as the first word in the sentence is not a number). If you wonder why number was set to 0, that's because on failure, the stringstream::operator>> zeros the argument (since C++11).
"If extraction fails, zero is written to value and failbit is set." ...
Before C++11, it left the argument unchanged. See the documentation for more details.
The correct way is to use a conversion from string to int (or long), namely std::stoi, and replace that line by
try{
number = std::stoi(word);
}
catch(std::exception& e){
std::cout << "error converting" << '\n';
}
Use stoi to parse the input like this:
int num = std::stoi(input);
using stoi is easy, and you can lazily catch the exception by the following:
if(!stoi(string)){
std::cout << "caught a non integer string" << endl;
}
I am stuck at this normalization part. I am using a string and reading data one by one. I keep getting blank. The program compiles. Any hints to what to do next would be awesome. How would I complete the 5 steps below? Steps 3 and 4 work fine.
A program that reads a text file using character-by-character I/O and performs the following normalization tasks:
Replaces all tab characters with 8 spaces
Replaces all upper-case letters with lower-case letters
All # symbols will be replaced by the word "at".
All = signs will be replaced by a series of 19 = signs.
When you find an asterisk, you will print a series of asterisks. The character following the asterisk indicates the number of asterisks to print. Use the ASCII value of the character following. Number of asterisks is ASCII value minus 32 plus 1. The character following the asterisk is used only as a counter, not a data character.
.
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
using namespace std;
int main() {
ifstream fin;
ofstream fout;
char fname[256];
char ofname[256];
char norm[256] = ".normal";
int count = 0;
//Opening input and output file
cout << "What file do you want to be normalized? \n";
cin >> fname;
cout << "\n";
fin.open(fname);
if (fin.fail()) {
cout << "Error opening input file! \n";
return 0;
}
strcpy( ofname, fname);
strcat( ofname, norm);
fout.open(ofname);
if (fout.fail()) {
cout << "Error opening output file! \n";
return 0;
}
cout << "Your output file name is: " << ofname << "\n";
//Normalization begins here
char data;
while (fin.get(data)) {
if (data == "\t") { //***
fout << " ";
}// else if (isupper(data)) { //***
// fout << tolower(data); //***
else if (data == "#") {
fout << "at";
} else if (data == "=") {
fout << "===================";
} else if (data == "*") {
fout << "some shit";
}
}
fin.close();
fout.close();
return 0;
}
[/code]
You were on the right track. Rather than a long winded explanation going line-by-line, I've included comments below. Your primary challenge is you were trying to read string data; where the intent of the problem seems to require char data; Also in reading character-by-character you need to include the stream modifier noskipws to insure you do not skip over whitespace characters. There are many, many ways to do this. This is just one example to compare against the approach you are taking:
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
using namespace std;
int main () {
ifstream fin;
ofstream fout;
char fname[256];
char ofname[256];
char norm[256] = ".normal";
char eq[] = "==================="; // set a convenient 19 char sting of '='
//Opening input and output file
cout << endl << " Enter name of file to be normalized: ";
cin >> fname;
cout << endl;
fin.open (fname);
if (fin.fail ()) {
cout << "Error opening input file! \n";
return 0;
}
strcpy (ofname, fname);
strcat (ofname, norm);
fout.open (ofname);
if (fout.fail ()) {
cout << "Error opening output file! \n";
return 0;
}
cout << endl << " Your output file name is: " << ofname << endl << endl;
//Normalization begins here
char data; // declare data as 'char' not 'string'
fin >> noskipws >> data; // read each char (including whitespace)
while (!fin.eof ()) {
switch (data)
{
case '\t' : // replace 'tab' by '8 chars'
fout << " ";
break;
case '#' : // replace '#' by 'at'
fout << "at";
break;
case '=' : // replace '=' by series of 19 '='
fout << eq;
break;
case '*' : // replace '*n' by series of (ascii n - 31) '*'
// fin >> count;
fin >> data; // read next value
if (fin.eof ()) // test if eof set
break;
for (int it=0; it < data - 31; it++) // output calculate number of asterisks
fout << '*';
break;
default: // use default case to proccess all data and
if (isupper (data)) { // test upper/lower-case.
char lc = tolower (data);
fout << lc;
} else {
fout << data;
}
}
fin >> noskipws >> data; // read the next character
}
fin.close (); // close files & return
fout.close ();
return 0;
}
Test Input:
$ cat dat/test.dat
A program that reads a text:
Tab ' ' -> 8 spaces.
U-C letters -> l-c letters.
All # -> "at".
All = signs -> a series of 19 = signs.
All 'asterisks''n' like '*6'. -> n series of asterisks
(Where Number of Asterisks is ASCII value minus 32 plus 1).
Output:
$ cat dat/test.dat.normal
a program that reads a text:
tab ' ' -> 8 spaces.
u-c letters -> l-c letters.
all at -> "at".
all =================== signs -> a series of 19 =================== signs.
all 'asterisks''n' like '***********************'. -> n series of asterisks
(where number of asterisks is ascii value minus 32 plus 1).
I am trying to read a txt file and store the content as variables. But the problem is that the txt file can have different contents. like for example,
txt1:
2 5000
P 900 15 200 L(1) 300 U(1) 400
A 2 10 500
txt2:
4 5000
P 350 81 10 L(1) 90 U(1) 300
P 500 50 100 L(5) 90 L(4) 90 L(3) 90 U(3) 90 U(4) 10 U(5) 100
A 1 90 500
A 7 93 50 L(1) 100 U(1) 300
So i have written a code that considers the following assumption,
line starting with 'A' has 3 parameters and with 'P' has 7 as in example 1. I do not know how to convert it to be generic.
The code is
#include <iostream>
#include <fstream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
struct specs
{
int ttime,priority,iter1,iter_lock,iter_unlock,event;
char lock_num[4];
char unlock_num[4];
char unlockid,lockid;
}obj[100];
int main()
{
int i,j,k;
int num_thread,time;
char t[200];
ifstream in("data.txt");
if ( !in )
{
cout << "Error: Can't open the file named data.txt.\n";
exit(1);
}
in >> num_thread;
in >> time;
cout << "Number of threads = "<< num_thread << endl ;
cout << "Total time is = " << time << endl;
for (k = 0; k < num_thread;k++)
{
in >> t[k];
if (t[k] == 'A')
{
in >> obj[k].event;
in >> obj[k].priority;
in >> obj[k].iter1;
cout << obj[k].iter1<<endl;
}
else if (t[k] == 'P' )
{
in >> obj[k].ttime;
in >> obj[k].priority;
in >> obj[k].iter1;
in >> obj[k].lock_num;
in >> obj[k].iter_lock;
in >> obj[k].unlock_num;
in >> obj[k].iter_unlock;
cout << obj[k].unlock_num<<endl;
cout << obj[k].iter_lock<<endl;
obj[k].unlockid = obj[k].unlock_num[2];
obj[k].lockid = obj[k].lock_num[2];
cout<< obj[k].unlockid <<endl;
cout<< obj[k].lockid <<endl;
int xx = obj[k].unlockid - '0';
cout << xx<<endl;
}
else cout << " Invalid parameter";
}
in.close();
return 0;
}
There are a number of ways to do this, each with varying levels of complexity depending on what you want to do with the data.
Given the constraints of your data, I assume that at some point you wish to parse the numeric items into numbers and the string items into strings.
However, as your input isn't fixed and the type (string or int) vary in ordering, this is potentially problematic.
One way is to use the whitespace to your advantage and tokenize the data into strings, then parse the tokens to determine if they are strings or numbers, and store them accordingly in their own separate containers.
To that end, I've done the first part of breaking the file and lines into tokens and storing and outputting them in the following:
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cstdlib>
#include <sstream>
using namespace std;
int main() {
string filename = "txt1.txt";
string temp;//a temporary variable used to store string data
vector < vector <string> > tokens;
vector < vector <string> >::iterator it;//used to iterate over `tokens`
//used to iterate over the individual elements of `token`
vector <string>::iterator jt;
//initialize the `ifstream` object with the filename
ifstream ifile(filename.c_str());
//check to see if the file opened correctly
if (ifile.is_open()) {
//the file has been opened, now operate on it
//by parsing over it and breaking each constituent line
//into tokens:
while(getline(ifile, temp)) {
//initialize the string stream with the line that
//was stored with getline:
istringstream iss(temp);
//this is a temporary vector to store the tokens per line
vector <string> tokens_in_line;
//use the whitespace to your advantage by using the
//extraction operator to parse over the tokens
//in each line and store them in the temporary vector (above)
while(iss >> temp) {
tokens_in_line.push_back(temp);
}
//at this point we may or may not have data in the temporary
//vector. Check to see if its empty, if so reject storing it
if (!tokens_in_line.empty()) {
tokens.push_back(tokens_in_line);
}
}
}
else {
cerr << "There was an error opening the input file!" << endl;
exit(1);
}
ifile.close();
//now output the information:
for (it = tokens.begin(); it != tokens.end(); ++it) {
for (jt = it->begin(); jt != it->end(); ++jt) {
cout << *jt << " ";
}
cout << endl;
}
return 0;
}
All you have to do at this point is figure out how to store the data for the strings and numbers in their own separate containers for later access. While that may seem daunting, if you follow my comments, it should be easy to figure out what to do and where to do it.
UPDATE:
Regarding parsing the string tokens for the integer numbers, you can do something like this for those tokens (I've implemented it this way, as it's possible that the integer can be greater than a single digit):
std::string numbers = "0123456789";
std::string token = "L(1)";
std::size_t begin = token.find_first_of(numbers.c_str());
std::size_t end = token.find_last_of(numbers.c_str());
std::string num_str = input2.substr(begin, end-1);
std::cout << num_str << std::endl;
All you have to do at this point is convert the num_str value to an integer. There's one caveat to this though: it assumes that the numbers are contiguous and occur only once - otherwise, you'll have problems.
I need to copy one line of text from a text file in c++, I have a program to find the line inwhich a word resides, so I decided if I could just take each individual line and load it into a string I could search line by line, string by string to find the correct word and its position (in characters, not lines) in the file. Help would be greatly appreciated.
edit: I found the code I am using to locate the line
#include <cstdlib>
#include <iostream>
#include <string>
#include <fstream>
#include <cstring>
#include <conio.h>
using namespace std;
int main()
{
ifstream in_stream; //declaring the file input
string filein, search, str, replace; //declaring strings
int lines = 0, characters = 0, words = 0; //declaring integers
char ch;
cout << "Enter the name of the file\n"; //Tells user to input a file name
cin >> filein; //User inputs incoming file name
in_stream.open (filein.c_str(), ios::in | ios::binary); //Opens the file
//FIND WORDS
cout << "Enter word to search: " <<endl;
cin >> search; //User inputs word they want to search
while (!in_stream.eof())
{
getline(in_stream, str);
lines++;
if ((str.find(search, 0)) != string::npos)
{
cout << "found at line " << lines << endl;
}
}
in_stream.seekg (0, ios::beg); // the seek goes here to reset the pointer....
in_stream.seekg (0, ios::beg); // the seek goes here to reset the pointer.....
//COUNT CHARACTERS
while (!in_stream.eof())
{
in_stream.get(ch);
cout << ch;
characters ++;
}
//COUNT WORDS
in_stream.close ();
system("PAUSE");
return EXIT_SUCCESS;
}
You only need one loop to accomplish this. Your loop should look something like this:
while (getline(in_stream, str))
{
lines++;
size_t pos = str.find(search, 0);
if (pos != string::npos)
{
size_t position = characters + pos;
cout << "found at line " << lines << " and character " << position << endl;
}
characters += str.length();
}
I also recommend you don't mix int and size_t types. For example, characters should be declared as size_t, not int.