删除显示的字符

时间:2015-03-29 15:48:48

标签: c escaping kernighan-and-ritchie

我正在使用" C编程语言"进行练习。 Brian W. Kernighan撰写的第2版& Dennis M. Ritchie。

练习1.9 让我困惑。所以这就是:

  

"编写一个程序将其输入复制到输出,用一个空格替换每一个空格的字符串"。

我很困惑这个。我在这里发布我的问题,因为其他学习者并没有像我想要的那样做这个练习。在这里,使用-来表示空白:

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('\0'); /* 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('\0');
  return EXIT_SUCCESS;
}  

|是一个游标。

Output: b|

但是当我添加换行符时,它不起作用。如何使用换行符?

2 个答案:

答案 0 :(得分:0)

所需的算法应该是这样的:

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

答案 1 :(得分:0)

代码的问题在于,只要您处理完字符就会打印字符,并且一旦检测到它们必须压缩到一个空格,就会尝试擦除它们。

您的方法是有效的,但您必须首先知道\b仅使光标返回一个空格(不删除),因此正确的方法是发出\b \b(退格,用于覆盖字符的空间和另一个用于将光标留在正确位置的退格键。

另一种方法是等待打印任何内容,直到我们知道该行是否以非空白字符串终止,或者它是否仅以\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&amp; R第二版完全兼容,因此您只需编译并运行。

或许最难以遵循的声明是中间的printf()行。星号*允许我使用printf参数指定字段的宽度,并且传递空字符串""允许我打印带有nblanks空格的字符串。最终的%c格式是打印刚刚读取的非空白字符。这导致了紧凑而有效的代码。

最后,你有一些错误的想法:

  • \b只返回终端中的一个字符(一个字符,而不是一行)。我不仅在打印到终端或打印机时工作。它不适用于文件(该文件会将退格作为普通字符放在里面)
  • \r使光标转到第一个显示列。这仅适用于屏幕和打印机。它不能在文件中工作,它将作为普通字符包含在内。
  • \0是C程序用来完成字符串的字符(知道它们在内存中的位置)它不是输出设备的特殊字符,它什么也不做(它是ASCII NUL字符) ,在输出终端上什么都不做)
  • 最后,如果您尝试在打印机上遵循\b \b方法,它将不会删除空白,因为空间不会擦除已打印的内容。那么,你必须遵循第二种方法。