int main(){
std::cout << "Insert file name / or path. \n NOTE: ONLY INPUTS. DELETES PREVIOUS DATA.\nV.6" << std::endl;
std::string filen;
std::cin >> filen;
std::ofstream myFile;
try{
myFile.open(filen, std::ios::out);
}
catch(std::fstream::failure){
std::cout << "Could not open file!\n Make sure the name and data type are valid.";
system("pause");
}
while(true){
int press = getch();
if(press == 43) myFile.close();
if(press == 8){myFile << "\b" << " " << "\b";std::cout << "\b" << " " << "\b" << std::flush;}
if(press == 13){ myFile << "\n"; std::cout << "\n" << std::flush;}
if(press != 43 && press != 127 && press != 13 && press != 8){myFile << (char)press;std::cout << (char)press;}
}
return 0;
}
Whenever I choose a text file and I press backspace, and I check the document and when I check the text document, I get random characters like so:
Those are not "random characters"; those are backspace characters! i.e. exactly the input you gave.
This can be verified with a hex editor (or piping the output of your program through hexdump et al).
If you wish to replicate the behaviour of common shells, you'll have to write your own code to identify the backspace character and, instead of appending it to myFile, instead eliminate the previously-entered character.
As #BoundaryImposition pointed out already, writing "\b" to your file, will actually write a binary backspace character to your file. What you probably want instead is myFile.seekp(-1, std::ios_base::cur);. If you are on win/dos machine you likely need extra care with '\n' characters because they are translated into 0x0d 0x0a when written to a text stream (thus they require to seek back 2 positions instead of 1).
But generally, if you are not dealing with very huge files, it will be way easier to just store the content in a std::string (using pop_back or erase, to remove characters if needed) and write it to the file when you are finished.
Related
My goal is to read from an input file and count the number of lines that have at least 1 lowercase letter and 1 digit. I have already solved the rest of my code which counted all of the lowercase, uppercase, digits, characters and words no problem. I have also read from the input file and reversed the lines word by word. I cannot seem to figure out why the code is counting 8 lines when there are only 7 with 1 lowercase and 1 digit. While using getline() for all of the other loops, I've had no issues. I'm not looking specifically for someone to write the code for me. I'd just like an explanation of why this is happening if possible?
My input file contains:
This is a test file for hw3
How many Uppercase letters are in this f1le?
How many Lowercase letters are in this F1le?
H0W mAnY dIg1ts ar3 1N in this FILe?
Turn the 1npU7 N4m3 int0 its reverse
reverse the Lines to their opp05173 coutnerpart
find tOTal NumbEr of characTer5 in F1le
THIS IS A TEST LINE
My code for this section is:
inFile.clear();
inFile.seekg(0, inFile.beg);
while(getline(inFile, line)){
wordInput.str(line);
wordInput.clear();
wordInput.seekg(0);
while(wordInput.get(c)){
if(islower(c)){
lowerCase++;
}
else if(isdigit(c)){
digit++;
}
}
if(lowerCase >= 1 && digit >= 1){
lineCount++;
}
}
cout << lineCount << endl;
return 0;
}
I have initialized all of my int variables to 0 and the top and I have declared my sstream variables as well. My libraries include <sstream> <fstream> <string> <iostream> and <algorithm> (which was used for earlier parts.
The output I am getting is
8
when it should be 7. The final line should not be counted as it has no lowercase letters and no digits. I am thinking that the first line is being read a second time and then stopping. I am in an intro to C++ class and have yet to learn how to use the debugger. Thank you in advance.
You made it clear that that you initialise all int variables to 0, which is great; however, let's have a look at your code (formatted so the indentation makes more sense):
// read line from file
while(getline(inFile, line))
{
wordInput.str(line);
wordInput.clear();
wordInput.seekg(0);
// read character
while(wordInput.get(c))
{
if(islower(c))
{
lowerCase++;
}
else if(isdigit(c))
{
digit++;
}
}
if(lowerCase >= 1 && digit >= 1){
lineCount++;
}
}
Here you read a line, and go through all characters on that line, and if you find a lowercase character, or a digit, you increment a variable. What happens when you read the next line? You haven't reset those variables back to 0, so upon reading the next line they would both be above 1 already.
You need the following:
while(getline(inFile, line))
{
wordInput.str(line);
wordInput.clear();
wordInput.seekg(0);
// We're about to start reading this line, so obviously we haven't found any yet
digit = 0;
lowerCase = 0;
Better yet, you can probably just declare those variables within the read line while loop:
while(getline(inFile, line))
{
int digit = 0;
int lowerCase = 0;
Although you haven't been taught to use a debugger, a great way of debugging is with cout statements. Put some print statements in to determine what all your variables are at any given time:
while(getline(inFile, line))
{
std::cout << "read line " << line << std::endl;
while(wordInput.get(c))
{
std::cout << "lowercase found so far: " << lowerCase << std::endl;
std::cout << "digits found so far: " << digit << std::endl;
if(islower(c))
{
std::cout << "lowercase character found: " << c << std::endl;
lowerCase++;
}
else if(isdigit(c))
{
std::cout << "digit found: " << c << std::endl;
digit++;
}
}
if(lowerCase >= 1 && digit >= 1)
{
std::cout << "found a lowercase character (" << lowerCase << ") or a digit (" << digit << ")" << std::endl;
lineCount++;
}
}
It's been awhile since I have coded in C++. There are other ways to debug than a debugger program.
I would add cout << line << endl; to your first while loop. That way you can output how the lines are being read and if any are being repeated. Also check your islower(char) and isdigit(char) functions to make sure they are reading appropriate ascii ranges.
I'm trying to output the plaintext contents of this .exe file. It's got plaintext stuff in it like "Changing the code in this way will not affect the quality of the resulting optimized code." all the stuff microsoft puts into .exe files. When I run the following code I get the output of M Z E followed by a heart and a diamond. What am I doing wrong?
ifstream file;
char inputCharacter;
file.open("test.exe", ios::binary);
while ((inputCharacter = file.get()) != EOF)
{
cout << inputCharacter << "\n";
}
file.close();
I would use something like std::isprint to make sure the character is printable and not some weird control code before printing it.
Something like this:
#include <cctype>
#include <fstream>
#include <iostream>
int main()
{
std::ifstream file("test.exe", std::ios::binary);
char c;
while(file.get(c)) // don't loop on EOF
{
if(std::isprint(c)) // check if is printable
std::cout << c;
}
}
You have opened the stream in binary, which is good for the intended purpose. However you print every binary data as it is: some of thes characters are not printable, giving weird output.
Potential solutions:
If you want to print the content of an exe, you'll get more non-printable chars than printable ones. So one approach could be to print the hex value instead:
while ( file.get(inputCharacter ) )
{
cout << setw(2) << setfill('0') << hex << (int)(inputCharacter&0xff) << "\n";
}
Or you could use the debugger approach of displaying the hex value, and then display the char if it's printable or '.' if not:
while (file.get(inputCharacter)) {
cout << setw(2) << setfill('0') << hex << (int)(inputCharacter&0xff)<<" ";
if (isprint(inputCharacter & 0xff))
cout << inputCharacter << "\n";
else cout << ".\n";
}
Well, for the sake of ergonomy, if the exe file contains any real exe, you'd better opt for displaying several chars on each line ;-)
Binary file is a collection of bytes. Byte has a range of values 0..255. Printable characters that can be safely "printed" form a much narrower range. Assuming most basic ASCII encoding
32..63
64..95
96..126
plus, maybe, some higher than 128, if your codepage has them
see ascii table.
Every character that falls out of that range may, at least:
print out as invisible
print out as some weird trash
be in fact a control character that will change settings of your terminal
Some terminals support "end of text" character and will simply stop printing any text afterwards. Maybe you hit that.
I'd say, if you are interested only in text, then print only that printables and ignore others. Or, if you want everything, then maybe write them out in hex form instead?
This worked:
ifstream file;
char inputCharacter;
string Result;
file.open("test.exe", ios::binary);
while (file.get(inputCharacter))
{
if ((inputCharacter > 31) && (inputCharacter < 127))
Result += inputCharacter;
}
cout << Result << endl;
cout << "These are the ascii characters in the exe file" << endl;
file.close();
Program openes input file and prints current reading/writing position several times.
If file is formated with '\n' for newline, values are as expected: 0, 1, 2, 3.
On the other side, if the newline is '\r\n' it appears that after some reading, current position returned by all tellg() calls are offsetted by the number of newlines in the file - output is: 0, 5, 6, 7.
All returned values are increased by 4, which is a number of newlines in example input file.
#include <fstream>
#include <iostream>
#include <iomanip>
using std::cout;
using std::setw;
using std::endl;
int main()
{
std::fstream ioff("su9.txt");
if(!ioff) return -1;
int c = 0;
cout << setw(30) << std::left << " Before any operation " << ioff.tellg() << endl;
c = ioff.get();
cout << setw(30) << std::left << " After first 'get' " << ioff.tellg() << " Character read: " << (char)c << endl;
c = ioff.get();
cout << setw(30) << std::left << " After second 'get' " << ioff.tellg() << " Character read: " << (char)c << endl;
c = ioff.get();
cout << setw(30) << std::left << " Third 'get' " << ioff.tellg() << "\t\tCharacter read: " << (char)c << endl;
return 0;
}
Input file is 5 lines long (has 4 newlines), with a content:
-------------------------------------------
abcd
efgh
ijkl
--------------------------------------------
output (\n):
Before any operation 0
After first 'get' 1 Character read: a
After second 'get' 2 Character read: b
Third 'get' 3 Character read: c
output (\r\n):
Before any operation 0
After first 'get' 5 Character read: a
After second 'get' 6 Character read: b
Third 'get' 7 Character read: c
Notice that character values are read corectly.
The first, and most obvious question, is why do you expect any
particular values when teh results of tellg are converted to
an integral type. The only defined use of the results of
tellg is as a later argument to seekg; they have no defined
numerical significance what so ever.
Having said that: in Unix and Windows implementations, they will
practically always correspond to the byte offset of the
physical position in the file. Which means that they will have
some signification if the file is opened in binary mode; under
Windows, for example, text mode (the default) maps the two
character sequence 0x0D, 0x0A in the file to the single
character '\n', and treats the single character 0x1A as if it
had encountered end of file. (Binary and text mode are
indentical under Unix, so things often seem to work there even
when they aren't guaranteed.)
I might add that I cannot reproduce your results with MSC++.
Not that that means anything; as I said, the only requirements
for tellg is that the returned value can be used in a seekg to
return to the same place. (Another issue might be how you
created the files. Might one of them start with a UTF-8
encoding of a BOM, for example, and the other not?)
So I'm trying to design a program that inputs a file and then reads through the lines and takes each line and outputs info about it to a new file.
I have it all down... except! All my .txt files are filled with garbage instead of what they should be filled with.
I can not figure it out. If I cout the string I'm feeding into the ofstream, the right stuff prints on the screen.
fstream lineOutFile;
string newFileName;
stringstream linefile;
linefile << lineCt;
linefile >> newFileName;
newFileName += ".txt";
lineOutFile.open(newFileName.c_str());
if(!lineOutFile)
{
cerr << "Can't open output file.\n";
}
stringstream iss;
iss << "The corrected 5' x 3' complement of line " << lineCt <<
" is as follows - \n\n" << finalSeq << "\n\n\n\n" <<
"This line of DNA sequence is made up of " << cgContent <<
" C and G neucleotides.\n\n" << "It contains " << polyTCount <<
" Poly-T strings of more than 4 consecutive neucleotides. They are as follows. - \n" <<
polyTString << "\n\n There are " << cpgCount <<
" CpG sites. The locations are as follows - \n" << cpgString;
string storage;
storage = iss.str();
cout << storage;
lineOutFile << storage;
lineOutFile.close();
lineCt++;
}
I'm getting "潣牲捥整✵砠㌠‧" << This sort of craziness in my .txt files.
I get the right thing when I cout out the same sting immediately before!
Why are my .txt files garbage?
Why are you using fstream instead of ofstream?
The default for fstream is to open an existing file. The default for ofstream is to start with an empty file. Whatever is already in the file is probably causing your editor to interpret the data with the wrong encoding.
Try running
LANG=C your_program
And turn off encoding recognition in your editor. Even better - view your txt files with cat program.
I'm printing a bunch of strings as following:
cout<<count<<"|"<<newTime.time<<"|"<<newCat<<"|"<<newCon<<endl;
in which count is a counter, newTime.time is a string of time, and newCat and newCon are both strings.
The output is like following:
06:02:11:20:08|DB Mgr|Sending query: “SELECT * FROM users”
Apparently, it left out the count and "|". However, if I change the code into
cout<<count<<"|"<<endl;
cout<<newTime.time<<"|"<<newCat<<"|"<<newCon<<endl;
The output just turned into
2|
06:02:11:20:08|DB Mgr|Sending query: “SELECT * FROM users”
I was first thinking if this is the problem of buffer. I changed endl to flush but the problem still exists.
Thanks for any help.
It sounds like your time string may have a carriage return \r in it. If that's the case, then outputting using your first method will still output the count and separator, but the \r will return to the start of the line and begin overwriting it.
Your second method will not overwrite the count since it's on the previous line (a \r will have little visible effect if you're already at the start of the line).
If you're running on a UNIX-like platform, you can pipe the output through something like od -xcb (a hex dump filter) to see if there is a \r in the output.
Alternatively, if you have a string in your code, you can see if it contains a carriage return with something like:
std::string s = "whatever";
size_t pos = s.find ('\r');
if (pos != std::string::npos) {
// carriage return was found.
}
By way of example, the following program:
#include <iostream>
int main (void) {
std::string s1 = "strA";
std::string s2 = "\rstrB";
std::string s3 = "strC";
std::cout << s1 << '|' << s2 << '|' << s3 << '\n';
std::cout << "=====\n";
std::cout << s1 << '|' << '\n';
std::cout << s2 << '|' << s3 << '\n';
std::cout << "=====\n";
size_t pos = s2.find ('\r');
if (pos != std::string::npos)
std::cout << "CR found at " << pos << '\n';
return 0;
}
seems to output the following:
strB|strC
=====
strA|
strB|strC
=====
CR found at 0
but in fact that first line is actually:
strA|(\r)strB|strC
where (\r) is the carriage return.
And keep in mind you rarely need endl - it's effectively a \n with a flush which is not really necessary in most cases. You can just get away with using \n and let the automated flushing take care of itself.