I see a question in The C Programming Language. It's like this:
Write a program to copy its input to its output, replacing each tab by \t , each backspace by \b , and each backslash by \ . This makes tabs and backspaces visible in an unambiguous way.
Then I write a program like this:
#include<stdio.h>
int main(void)
{
int c;
while((c=getchar())!=EOF)
{
if(c=='\t')
{
putchar('\\');
putchar('t');
}
if(c=='\b')
{
putchar('\\');
putchar('b');
}
if(c=='\\')
{
putchar('\\');
putchar('\\');
}
else{
putchar(c);
}
}
return 0;
}
But when I input backspace, I can't get '\b', so how can I get the output '\b'? I.e., I mean, how can I output backspace?
Keyboard input is preprocessed by the operating system. Most characters are fed directly as input to your program, but some are handled specially.
On UNIX-like systems, standard input is usually line-buffered. The system reads a whole line of text and doesn't pass it on to your program until you press Enter. While reading that line, the system processes Backspace itself; rather than adding a backspace character to the buffer, it erases the most recent character. Your program never sees the '\b' character.
To enter a literal backspace character that can be seen by your program, on a UNIX-like system you can precede it with Ctrl-V. And depending on your tty and terminal emulator settings, typing the Backspace key might transmit an ASCII DEL character rather than backspace. To make sure your program sees a backspace character, type Ctrl-V Ctrl-H.
On non-UNIX-like systems (most likely Windows), there's probably a way to do something similar, but I don't know what it is.
You can also run your program with input from a file. Getting a literal backspace character into the input file is left as an exercise (it depends on the workings of your text editor).
The getchar function buffers the user input and sends it to your program only when the user presses Enter. As suggested, you must use getch() to detect each keypress.
Your code must be:
#include<stdio.h>
#include<conio.h>
int main(void)
{
int c;
while ((c = getch()) != EOF)
{
if (c == '\t')
{
putchar('\\');
putchar('t');
}
else if (c == '\b')
{
putchar('\\');
putchar('b');
}
else if (c == '\\')
{
putchar('\\');
putchar('\\');
}
else if (c == '\r')
{
putchar('\n');
}
else{
putchar(c);
}
}
return 0;
}
Enter is detected as \r by getch, so you have to manually replace it by \n if you want to go to the next line.
The backspace is usually eaten up by the shell. Use Ctrl + H to test for backspace.
See 5. Delete and Backspace for more detail.
In your code, you have three ifs with only one else at the end... so your else is only tied to the last if. For tab and backspace, since they're not a backslash, the last if test is false, and the else block executes printing the original character. This means after printing '\t' you print a tab (and likely see some empty space in your output), and after printing '\b' you print a backspace which eats the 'b' or causes it to get overwritten by the next character. To fix it, either use:
if(c == '\t')
{
putchar('\\');
putchar('t');
}
else if(c=='\b') /* "else if" rather than "if" */
{
putchar('\\');
putchar('b');
}
else if(c=='\\')
{
putchar('\\');
putchar('\\');
}
else{
putchar(c);
}
...or simply rewrite it with a switch:
switch(c)
{
case '\t':
puts("\\t");
break;
case '\b':
puts("\\b");
break;
case '\\':
puts("\\\\");
break;
default:
putchar(c);
}
Related
I would like to ask about inserting and deleting characters from string.
Here is the code:
void Edit::input() {
int len = 0;
COORD cord;
cord.X = _x;
cord.Y = _y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), cord);
while (true) {
char ch = _getch();
if (ch == 13)
{
break;
}
else if (ch == 8)
{
if (len == 0)
{
continue;
}
pusty.pop_back();
std::cout << "\b \b";
len--;
}
else if (len == 6) {
break;
}
else {
pusty.push_back(ch);
len++;
}
std::cout << ch;
}
}
What is the problem exactly? I've got the coordinates of X and Y of the window where text will be entered in this window, length of whole string is 6 characters. The problem is in a moment when i want to use backspace when len value is at the last element. Then backspace creates blank space on 7th index. The picture below shows the issue. How to avoid this problem ? Thanks for all feedbacks.
That extra space is due to using getch, which echos to the console as well as returning the character to you. This means that the 7th position on the console's output is reached and thus the background is painted.
You just need to set the background colour to black (in a similar manner to how you set it to turquoise in your example) before printing \b \b, then set it back to turquoise afterwards - this'll hide your phantom extra character.
Rather than using getch, you should really consider learning ncurses - it provides really helpful functions that can make life a lot easier in this sort of situation (like a getch equivalent that doesn't echo). And it's cross-platform, so you can use it on Windows.
I am trying to create a text box a user an input data into, it is going fine, however, whenever I try to set up the backspace key to delete the last character of the string, it doesn't seem to work even though countless tutorials have showed me this way.
if (event.type == sf::Event::TextEntered)
{
sentence += (char)event.text.unicode;
//if (sentence.getSize() < 16) {
//
if (event.text.unicode == 8)
{
sentence.erase(sentence.getSize() - 1, sentence.getSize());
}
text.setString(sentence);
break;
//}
}
Also, was wondering what would be the best way to stop the string from advancing 16 characters.
Nevermind, its not that hard, you're going to feel weird after what i'm going to say ^^
if (event.type == sf::Event::TextEntered) {
if (event.text.unicode == 8)
if (sentence.getSize())//If the string doesn't have any char, don't do anything
sentence.erase(sentence.getSize() - 1, sentence.getSize());
else //Don't add any character when you delete one
if(sentence.getSize() < 16)//Yeah, thats the best way to do it
sentence += (char)event.text.unicode;
text.setString(sentence);
break;
}
If you were pressing backspace, your program was adding it to the string and then deleting it... so... it wasn't doing anything ^^
I was seeking some help on an issue. I have to read certain "passwords" from a .txt file, like "abE13#" and do some simple error checking to make sure they fit certain requirements. But at the current moment, it's printing out the passwords (which is meant to be done), but it's ignoring the checking and gets stuck in a loop where new lines are being printed out. I'm sure it has to do something with while(ch!='\n') but I'm not all that sure what is needed there in place of that to check.
ch = inFile.get();
while(!inFile.eof())
{
while(ch != '\n')
{
cout << ch;
if(isalpha(ch))
{
charReq++;
if(isupper(ch))
uppercaseReq++;
else
lowercaseReq++;
}
else if(isdigit(ch))
{
charReq++;
digitReq++;
}
else if(isSpecial(ch))
{
charReq++;
specialCharReq++;
}
if(uppercaseReq < 1)
cout << "\n missing uppercase" << endl;
ch = inFile.get();
}
}
It's supposed to kind of follow this format,
Read a character from the password.txt file
while( there are characters in the file )
{
while( the character from the file is not a newline character )
{
Display the character from the file
Code a cascading decision statement to test for the various required characters
Increment a count of the number of characters in the password
Read another character from the password.txt file
}
Determine if the password was valid or not. If the password was invalid,
display the things that were wrong. If the password was valid, display that it
was valid.
Read another character from the file (this will get the character after the
newline character -- ie. the start of a new password or the end of file)
}
Display the total number of passwords, the number of valid passwords, and the
number of invalid passwords
It keeps prints because of this while(inFile). This is always true. Change it to an if statement just to check if file is open:
if ( inFile )
EDIT: It will stop at the first password because of this while(ch != '\n'). When he gets to the end of the first password ch will be '\n', while fails and stop reading. Change it to:
while( !inFile.eof() )
while( the character from the file is not a newline character )
You have converted this line of pseudocode into this line of c++ code:
while (ch != '\t')
'\t' is the tab character, not the newline character. This could definitely cause problems as to why you are never ending and instead just printing out new lines (Really EOF, but you don't see that).
'\n' is the newline character.
Give that a try.
EDIT:
Also, your only checking for an entire ifstream to be false. I don't quite know when that would happen, but I would recommend checking for the EOF flag. Your code should turn into something along the lines of this:
while( !inFile.eof() )
{
while(ch != '\n' && !inFile.eof() )
{
// ...
}
}
If you don't check for infile twice, you may end up in an infinite loop.
while(infile.good())
{
while (inFile.good() && ch != '\n')
{
...
}
if (ch == '\n')
{...}
else
{...}
}
c='q';
while(c=='q')
{
printf("hello");
scanf("%c",&c);
}
Why does the loop exit without any reason on taking the input?
The loop isn't exiting without reason. The scanf call will read a character from stdin and store it in c, thus changing the value of c. When the loop condition is tested, presumably c no longer == 'q' (e.g., you typed something other than "q").
If you're trying to loop until the user doesn't type "q":
do {
printf("hello");
scanf("%c", &c);
}
while (c != 'q');
But note that on most console systems, scanf won't return until the user has typed a full line of text and pressed enter. If you're looking to do key-by-key entry, you'll probably want to look at a different function.
I'm going to assume you want a user input of 'q' to mean quit, and you want the loop to exit when c == 'q'.
Try:
c='\0';
while(c !='q')
{
printf("hello");
scanf("%c",&c);
}
I'm working on an automatic summarization system in my C++ class and have a question regarding one of the ASCII comparisons I'm doing. Here's the code:
char ch;
string sentence;
pair<char, char> sentenceCheck;
int counter = 0;
while (!ifs2.eof())
{
ch = ifs2.get();
ch = tolower(ch);
if (ch == 13)
ch = ifs2.get();
if (ch != 10 && ch != '?' && ch != '!' && ch != '.')
sentence += ch;
sentenceCheck.first = sentenceCheck.second;
sentenceCheck.second = ch;
cout << sentenceCheck.first << "-" << (int)sentenceCheck.first << " ---- " << sentenceCheck.second << "-" << (int)sentenceCheck.second << endl;
if(sentenceCheck.second == ' ' || sentenceCheck.second == 10 || sentenceCheck.second == -1)
{
if(sentenceCheck.first == '?' || sentenceCheck.first == '!' || sentenceCheck.first == '.')
{
istringstream s(sentence);
while(s >> wordInSentence)
{
sentenceWordMap.insert(pair<string, int>(wordInSentence, 0));
}
//sentenceList.push_back(pair<string, int>(sentence, 0));
sentence.clear();
}
}
}
What is being done here (with the two if statements) is checking whether a new sentence has begun in the text that is to be analyzed and dealt with later. The conditionals work but only because we discovered that we have to check for that -1 as well. Any ideas what that represents?
-1 doesn't represent anything in ASCII. All ASCII codes are in the range [0, 127]. It's not even guaranteed by C++ that -1 is a valid value for a char.
The problem is that you're not checking the return value from ifs2.get(), which returns an int (not a char!) that may be -1 on end of file. The proper way to check for this is
int ch = ifs2.get();
if (!ifs2)
// break the loop
because the EOF value is not guaranteed to be -1 (it's actually std::char_traits<char>::eof()).
(Btw., you shouldn't write ASCII codes as magic numbers; use \n for linefeed, \r for carriage return.)
The while is incorrectly structured: you need to check eof() immediately after get():
for (;;)
{
ch = ifs2.get();
if (ifs2.eof()) break;
ch = tolower(ch);
if (ch == 13)
{
ch = ifs2.get();
if (ifs2.eof()) break;
}
...
}
The -1 is probably the EOF indicator.
Note (as has already been stated) get() returns an int, not a char.
As an ASCII character -1 doesn't represent anything (which is to say -1 is not a valid ASCII value). As the return value from get() it means that the read operation failed - most likely due to the end of file being reached.
Note that the eof() function doesn't return true if the next call to get will fail because of the end of file being reached - it returns true if the previous call to get failed because of the end of file being reached.
It's not ASCII, it's an error returned by istream::get
ch = ifs2.get();
It's probably EOF, i.e. you've run out of input.
The fact that checking for -1 works is an accident, and has nothing to
do with ASCII values (which only use 0 to 127). Your code will fail
if either plain char is unsigned (compile with /J with VC++, I think),
or EOF isn't -1 (rare, but all that's guaranteed is that it is
negative). You're code will also fail if the input happens to be
Latin-1, and it contains a 'ÿ'.
The basic problem in your code is that you're not checking for end of
file correctly. Putting the test at the top of the loop doesn't work;
you need to test for failure (not eof()) after input, before using
the value read. There are several ways of doing this; in your case, the
simplest is probably to use:
if ( !ifs2.get(ch) ) {
// Input failed...
}
Alternatively, you can make ch an int, and do:
ch = ifs2.get();
if ( ch == EOF ) {
// Input failed...
}
This has the advantage that the following call to tolower is no longer
undefined behavior (tolower takes an int, which must be in the range
[0...UCHAR_MAX] or EOF—if plain char is signed, you aren't
guaranteeing this). On the other hand, it doesn't allow chaining, i.e.
you can't write the equivalent of:
while ( ifs2.get( sentenceCheck.first )
&& ifs2.get( sentenceCheck.second ) ) {
// ...
}
(which could be useful in some cases).
FWIW: the technique you're using is something called a sliding window
into a stream, and it's worth pushing it off into a separate class to
handle the logic of keeping the window filled and up to date.
Alternatively, a simple state machine could be used for your problem.
And I'd definitely avoid using magic constants: if you want to check for
a carriage return, compare with '\r'. Similarly, newline is '\n',
and in the outer if, it looks like you want to check for whitespace
(isspace( static_cast<unsigned char>( sentenceCheck.second ) )),
rather than comparing for the values.
I might also add that your code fails to correctly handle sentences that
end with a quote, like This is the "text in your input."; it also
fails for abbreviations like Mr. Jones is here.. But those problems
may be beyond the scope of your assignment. (The abbreviations one is
probably not fully solvable: sometimes "etc." is the end of a
sentence, and sometimes it's not.)