擦除显示的字符
Erase the displayed characters
我正在做“C 编程语言”第 2 版的练习,作者是 Brian W. Kernighan 和 Dennis M. Ritchie。
练习 1.9 让我很困惑。所以这里是:
"Write a program to copy its input to output, replacing each string of one more blanks by a single blank".
我对此感到困惑。我 post 我的问题在这里,因为其他学习者没有像我想做的那样做这个练习。在这里,用-
表示一个空格:
Input: ----hello
Output: -hello
但我想要这个:
Input: ----hello
Output: ----hello
Input: ----
Output: -
这是我的程序:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int character; /* input character */
int non_blank = 0; /* is any non blank character */
while ((character = getchar()) != EOF) {
if (character != '\n') {
putchar(character);
if (character != ' ') {
non_blank = 1;
}
}
else {
if (non_blank == 0 ) {
putchar('\b'); /* go to previous line (blabla\n|cursor|) (blabla|cursor|\n) */
putchar('\r'); /* carriage return */
putchar(' '); /* put one space */
putchar('[=12=]'); /* and put the end of line */
}
non_blank = 0;
}
}
return EXIT_SUCCESS;
}
但空格不会被删除。
Input: ------|\n
Output: -|-----
这是我对转义序列的实验:
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("bbbbbbbbbbbbbbb");
putchar('\b'); /* jump to previous line */
putchar('\r');
putchar('b');
putchar('[=14=]');
return EXIT_SUCCESS;
}
|
是游标。
Output: b|
但是当我添加换行符时,它不起作用。如何使其与换行符一起使用?
所需的算法应类似于:
implement a state machine with two states. NotInSpaces and InSpaces
(with just two states, a boolean would work)
no special treatment for '\n'
set state to NotInSpaces
Loop: (exit loop on EOF)
getchar
if char is space
then if state is NotInSpaces
then set state to InSpaces
output space
endif
else
output char
endif
end Loop:
output '\n' // to force output buffer flush
您的代码的问题在于,您在处理字符后立即打印字符,并且在检测到必须将它们压缩为一个字符后尝试擦除它们 space。
你的方法是有效的,但你必须首先知道 \b
只会让光标返回一个 space (没有擦除),所以正确的方法是发出 \b \b
(一个后退space,一个space覆盖字符,另一个后退space将光标留在正确的位置)
另一种方法是等待打印任何内容,直到我们知道该行是以非空字符串结尾还是仅以 \n
字符结束。
以下代码对空白字符进行计数并管理两种状态来应对这种情况。当然,您将能够遵循代码,我已尝试用注释对其进行记录。
#include <stdio.h>
int main()
{
int c;
int state = 0;
int nblanks = 0;
/* read chars up to EOF */
while((c = getchar()) != EOF) {
switch (state) {
case 0: /* no nonblank character read */
switch (c) {
/* accumulate number of blanks to be printed in case
* we see a nonblank char before \n */
case ' ': nblanks++; break;
/* in this case we have seen nblanks before a \n, so
* we have to print only one blank and \n */
case '\n':
puts(" "); /* just one space */
nblanks = 0; /* reset counter */
break;
/* nonblank char */
default:
/* print all the blanks up to here */
printf("%*s%c", nblanks, "", c);
state = 1; /* switch state */
break;
} /* switch */
break;
/* we have read at least a nonblank char, so we must
* echo the line until the end. */
case 1:
if (c == '\n') {
state = 0;
nblanks = 0;
} /* if */
putchar(c);
break;
} /* switch */
} /* while */
} /* main */
完全兼容K&R第二版,只需要编译即可运行。
也许最难理解的语句是中间的 printf()
行。星号 *
允许我使用 printf 参数指定字段的宽度,传递空字符串 ""
允许我打印带有 nblanks
spaces 的字符串。最后的 %c
格式是打印刚刚读取的非空字符。这导致了紧凑而高效的代码。
最后,你的一些错误想法:
\b
仅返回终端中的一个字符(一个字符,而不是一行)。我不仅在打印到终端或打印机时有效。它不适用于文件(文件将返回 spaces 作为内部的普通字符)
\r
使光标移动到第一个显示列。这仅适用于屏幕和打印机。它在文件中不起作用,它作为普通字符包含在内。
[=21=]
是 C 程序用来结束字符串的字符(知道它们在内存中的什么位置结束)它不是输出设备的特殊字符,它什么都不做(它是 ASCII NUL 字符,在输出端什么也不做)
- 最后,如果您尝试在打印机上使用
\b \b
方法,它不会擦除任何内容,因为 space 不会擦除已经打印的内容。那么,就得采用第二种方法了。
我正在做“C 编程语言”第 2 版的练习,作者是 Brian W. Kernighan 和 Dennis M. Ritchie。
练习 1.9 让我很困惑。所以这里是:
"Write a program to copy its input to output, replacing each string of one more blanks by a single blank".
我对此感到困惑。我 post 我的问题在这里,因为其他学习者没有像我想做的那样做这个练习。在这里,用-
表示一个空格:
Input: ----hello
Output: -hello
但我想要这个:
Input: ----hello
Output: ----hello
Input: ----
Output: -
这是我的程序:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int character; /* input character */
int non_blank = 0; /* is any non blank character */
while ((character = getchar()) != EOF) {
if (character != '\n') {
putchar(character);
if (character != ' ') {
non_blank = 1;
}
}
else {
if (non_blank == 0 ) {
putchar('\b'); /* go to previous line (blabla\n|cursor|) (blabla|cursor|\n) */
putchar('\r'); /* carriage return */
putchar(' '); /* put one space */
putchar('[=12=]'); /* and put the end of line */
}
non_blank = 0;
}
}
return EXIT_SUCCESS;
}
但空格不会被删除。
Input: ------|\n
Output: -|-----
这是我对转义序列的实验:
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("bbbbbbbbbbbbbbb");
putchar('\b'); /* jump to previous line */
putchar('\r');
putchar('b');
putchar('[=14=]');
return EXIT_SUCCESS;
}
|
是游标。
Output: b|
但是当我添加换行符时,它不起作用。如何使其与换行符一起使用?
所需的算法应类似于:
implement a state machine with two states. NotInSpaces and InSpaces
(with just two states, a boolean would work)
no special treatment for '\n'
set state to NotInSpaces
Loop: (exit loop on EOF)
getchar
if char is space
then if state is NotInSpaces
then set state to InSpaces
output space
endif
else
output char
endif
end Loop:
output '\n' // to force output buffer flush
您的代码的问题在于,您在处理字符后立即打印字符,并且在检测到必须将它们压缩为一个字符后尝试擦除它们 space。
你的方法是有效的,但你必须首先知道 \b
只会让光标返回一个 space (没有擦除),所以正确的方法是发出 \b \b
(一个后退space,一个space覆盖字符,另一个后退space将光标留在正确的位置)
另一种方法是等待打印任何内容,直到我们知道该行是以非空字符串结尾还是仅以 \n
字符结束。
以下代码对空白字符进行计数并管理两种状态来应对这种情况。当然,您将能够遵循代码,我已尝试用注释对其进行记录。
#include <stdio.h>
int main()
{
int c;
int state = 0;
int nblanks = 0;
/* read chars up to EOF */
while((c = getchar()) != EOF) {
switch (state) {
case 0: /* no nonblank character read */
switch (c) {
/* accumulate number of blanks to be printed in case
* we see a nonblank char before \n */
case ' ': nblanks++; break;
/* in this case we have seen nblanks before a \n, so
* we have to print only one blank and \n */
case '\n':
puts(" "); /* just one space */
nblanks = 0; /* reset counter */
break;
/* nonblank char */
default:
/* print all the blanks up to here */
printf("%*s%c", nblanks, "", c);
state = 1; /* switch state */
break;
} /* switch */
break;
/* we have read at least a nonblank char, so we must
* echo the line until the end. */
case 1:
if (c == '\n') {
state = 0;
nblanks = 0;
} /* if */
putchar(c);
break;
} /* switch */
} /* while */
} /* main */
完全兼容K&R第二版,只需要编译即可运行。
也许最难理解的语句是中间的 printf()
行。星号 *
允许我使用 printf 参数指定字段的宽度,传递空字符串 ""
允许我打印带有 nblanks
spaces 的字符串。最后的 %c
格式是打印刚刚读取的非空字符。这导致了紧凑而高效的代码。
最后,你的一些错误想法:
\b
仅返回终端中的一个字符(一个字符,而不是一行)。我不仅在打印到终端或打印机时有效。它不适用于文件(文件将返回 spaces 作为内部的普通字符)\r
使光标移动到第一个显示列。这仅适用于屏幕和打印机。它在文件中不起作用,它作为普通字符包含在内。[=21=]
是 C 程序用来结束字符串的字符(知道它们在内存中的什么位置结束)它不是输出设备的特殊字符,它什么都不做(它是 ASCII NUL 字符,在输出端什么也不做)- 最后,如果您尝试在打印机上使用
\b \b
方法,它不会擦除任何内容,因为 space 不会擦除已经打印的内容。那么,就得采用第二种方法了。