reading from text file and changing values c++ - c++

#include <iostream>
#include <fstream>
#include <iomanip> // For formatted input
#include <cctype> // For the "is" character functions
#include <cstring> // For strncpy, strncat and strlen functions
#include <cstdlib> // For exit function
using namespace std;
int main() {
ifstream fin; // Declare and name the input file stream object
ofstream fout; // Declare and name the output file stream object
char in_file[51]; // Filename for the input file
char out_file[56]; // Filename for the output file
char c; // Current character in the file
cout << "Enter the filename of the input file: ";
cin >> setw(51) >> in_file; //setting max length of file name
strncpy(out_file, in_file, 50);
strncat(out_file, ".norm", 50 - strlen(out_file));
fin.open(in_file);
if(fin.fail()) {
cout << "Cannot open " << in_file << " for reading.\n";
exit(1);
}
fout.open(out_file);
if(fout.fail()) {
cout << "Cannot open " << out_file << " for writing.\n";
exit(1);
}
while(fin.get(c))
{
/* commented this out to see if a switch statement would output differently
if (isupper(c))
{
c=tolower(c);
putchar(c);
}
if (c=='/n')
{
fout<< endl << endl;
}
if (c=='/t')
{
for(int i=0; i<9; i++)
fout<<" ";
}
*/
switch (c)
{
case '\t' : // replace 'tab' by '8 chars'
fout << " ";
break;
case '\n' : //replace 1 newline with 2
fout<<"\n"<<"\n";
break;
default: // use default case to proccess all data and
if (isupper (c)) { // test upper/lower-case.
char c2 = tolower (c);
fout << c2;
} else {
fout << c;
}
}
fin >> noskipws >> c; // read the next character
}
fin.close();
fout.close();
cout << in_file << " has been normalized into " << out_file << endl;
return(0);
}
What I'm trying to do is have some input text file, append it with .norm and output it normalized with: 1.All tabs replaced with 8 spaces, 2.All upper case to lower case, 3.Double space the text. I thought my code would accomplish this, but I'm getting really weird outputs.
Here's an example of a text input:
DOE JOHN 56 45 65 72
DOE jane 42 86 58 69
doe tom 89 92 75 86
which then was output to:
dejh 64 57
o ae4 65 9detm8 27 6
I have no idea what's going wrong and would really appreciate any help.

while(fin.get(c))
reads a character at the beginning of every iteration of the while loop. But inside the while loop body, right at the end
fin >> noskipws >> c;
reads another character. This second character will be promptly written over by while(fin.get(c)) and never be inspected.
This is shown by the OP's output: Every second character is transformed and written to the file.
Recommendation to OP: Learn to use your IDE's debugger. This was a trivial error that would have been immediately apparent if OP stepped through a few loop iterations.

Related

Getline(); extraction stops with the 1A character

so I don't know how to explain this correctly but gonna try my best.
I'm trying to save a file into a string, it's not a .txt file, it's a .umsbt file so it has weird ASCII characters (like 00, 0A, 0E, 1A...) so when I save the .umsbt into the string using getline(); and then print it using cout, the whole file isn't printed, and when I open the actual file through HxD (hex editor) I see that the print stopped before a 1A character, did some tests and it's the 1A character's fault.
This is my code
#include <iostream>
#include <stdlib.h>
#include <fstream>
#include <string>
#include <string.h>
#include <conio.h>
#include <sstream>
using namespace std;
string line; //the file is stored here
string name; //name of the file
void printfile() {
int o = 0;
int fileCount;
ifstream file;
file.open(name, ios::in);
if (file.fail()) {
cout << "Not found \n";
cin.get();
cin.get();
exit(1);
}else {
file.seekg(0, ios::end);
fileCount = file.tellg();
file.seekg(0);
while (!file.eof()) {
getline(file, line);
cout << "file character count: " << fileCount << endl;
cout << "string character count: " << line.length() << "\n" << endl;
for (int i = 0; i < line.length(); i++) {
cout << line[i];
o++;
if (o == 16) {
cout << "\n";
o = 0;
}
}
}
file.close();
}
}
int main()
{
cin.ignore(26, '\n');
cout << "Write the name of your file (.umsbt included) \n" << endl;
cin >> name;
cout << "\n";
printfile();
cin.get();
cin.get();
return 0;
}
Hope someone can help me, I'm currently trying to remove/replace all of the 1A characters in any file, and the restriction is that you have to do it in the ifstream itself, cause you can't save it in a string (will cause the problem with 1A and the file won't be fully saved)
(Here's a pic of the file opened up in HxD hope you get an idea of it https://imgur.com/a/1uQzOPq)
Thank you in advance
Seems that you are using binary files and not a normal text file.
Check out these links to learn about binary files.
https://study.com/academy/lesson/writing-reading-binary-files-in-c-programming.html
https://computer.howstuffworks.com/c39.htm
Bye,
Samuel

Am i using ifstream::fail() method in bad way?

I have the txt file which contains for example:
Arthur 20
Mark 21
Josh 12
The are no empty lanes between, its only for readability!
What I want to do is write it on the screen in the same way as it is in the file.
I tried to make it this way:
ifstream file;
string word;
file.open("data.txt");
while(!file.eof()){
file >> word;
if(file.fail())
break;
cout << word << " ";
file >> word;
cout << word << endl;
}
But the output is:
Arthur 20
Mark 21
Josh 12
0
So why this 0 is being caught as a empty line to my string variable? I thought that fail() should stop the loop and leave me with correct output?
as long as you have names which don't contain white spaces and age as integer then you can read name as a string and age as an integer.
you don't need to check whether the file was successfully opened or not you can just abbreviate the operation:
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::ifstream file;
std::string word;
int age;
file.open("data.txt");
while( file >> word)
{
file >> age;
std::cout << word << " " << age << std::endl;
}
std::cout << std::endl;
return 0;
}
if you want to use one variable and for sure a string one then:
while( file >> word)
{
std::cout << word << " ";
file >> word;
std::cout << word << std::endl;
}
I don't see any good thing to read age as a string and maybe later convert it back to an integer!
the output:
Arthur 20
Mark 21
Josh 12

Unexpected repetition while extracting integers from string in c++ using stringstream

I am trying to read a file which consist of lines that are made of space separated integers. I want to store each line as a separate vector of integers.
so I tried reading input line by line and extracting integers from it using
stringstream
The code I have used for extraction is as follows -
#include <bits/stdc++.h>
using namespace std;
int main()
{
freopen("input.txt","r",stdin);
string line;
while(getline(cin, line)) {
int temp;
stringstream line_stream(line); // conversion of string to integer.
while(line_stream) {
line_stream >> temp;
cout << temp<< " ";
}
cout << endl;
}
return 0;
}
Above code works but it repeats the last element.For example, input file -
1 2 34
5 66
output:
1 2 34 34
5 66 66
How can I fix this?
Because of this:
while(line_stream) {
line_stream >> temp;
cout << temp<< " ";
}
which fails for the same reason that while (!line_stream.eof()) would fail.
When you have read the last integer, you haven't reached the end of the stream yet - that will happen on the next read.
And the next read is the unchecked line_stream >> temp;, which will fail and leave temp untouched.
The proper form for such a loop is
while (line_stream >> temp)
{
cout << temp<< " ";
}

reading data from text files in c++ and changing the values

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).

Simple noob I/O question (C++)

sorry for the noob question, but I'm new to C++.
I need to read some information, line-by-line, from a file, and perform some calculations, and output into another file. For example, we read a unique ID for each line, a name, and 2 numbers. The last 2 numbers are multiplied, and in the output file, the ID, name and product are printed line by line:
input.txt:
2431 John Doe 2000 5
9856 Jane Doe 1800 2
4029 Jack Siu 3000 10
output.txt:
ID Name Total
2431 John Doe 10000
9856 Jane Doe 3600
4029 Jack Siu 30000
My code is similar to this, but only the first line appears in the output file. If I press Enter repeatedly, the other lines appear in the output file:
#include <fstream>
using namespace std;
ifstream cin("input.txt");
ofstream cout("output.txt");
int main () {
int ID, I, J;
string First, Last;
char c;
cout << "ID\tName\t\Total\n";
while ((c = getchar()) != EOF) {
cin >> ID >> First >> Last >> I >> J;
cout << ID << " " << First << " " << Last << " " I * J << "\n";
}
return 0;
}
That's my only problem, that the values don't appear in the output file, unless I press Enter repeatedly, then close the program. Can anyone suggest a fix for my code above, to have it do the task without keyboard input? Thanks!
Use
while (!cin.eof()) {
using namespace std;
ifstream cin("input.txt");
ofstream cout("output.txt");
You've hidden the real std::cin and std::cout...and will later read from them.
while ((c = getchar()) != EOF) {
But here you use the real std::cin to check for EOF.
The getchar() call reads waits for you to type a character (and press Enter) since it reads from stdin (standard input). Try changing the loop condition to stop reading when cin reaches end of file.
EDIT
You should also use different names for input and output streams -- there are already cin and cout in the std namespace.
This is because you used getchar() in your while loop condition. Not sure what you were trying to do, but getchar() reads a char from stdin. What you should have done, is check if cin failed or encountered EOF.
While I was looking for the answer I though I better check and make sure it worked. I got some build errors and got a little carried away from there.
Hope this helps!
#include <iostream>
#include <fstream>
using namespace std;
int main () {
ifstream indata("input.txt");
if(!indata)
{ // file couldn't be opened
cerr << "Error: input.txt could not be opened" << endl;
exit(1);
}
ofstream output("output.txt");
if(!output)
{ // file couldn't be opened
cerr << "Error: output.txt could not be opened" << endl;
exit(1);
}
int ID, I, J;
char First[10], Last[10];
output << "ID\tName\tTotal\n";
while (!indata.eof())
{
indata >> ID >> First >> Last >> I >> J;
output << ID << " " << First << " " << Last << " " << I * J << endl;
}
indata.close();
output.close();
return 0;
}