删除当前打印的控制台行

2024-10-12 09:08:00
admin
原创
72
摘要:问题描述:如何在 C 中清除当前打印的控制台行?我正在使用 Linux 系统。例如 -printf("hello"); printf("bye"); 我想在同一行上打印 bye 来代替 hello。解决方案 1:您可以使用VT100 转义...

问题描述:

如何在 C 中清除当前打印的控制台行?我正在使用 Linux 系统。例如 -

printf("hello");
printf("bye");

我想在同一行上打印 bye 来代替 hello。


解决方案 1:

您可以使用VT100 转义码。大多数终端(包括 xterm)都支持 VT100。要删除一行,可以使用以下代码^[[2K。在 C 语言中,代码如下:

printf("
");

解决方案 2:

一些值得注意的微妙之处...

删除光标当前所在的整行

将光标向上移动一行,但在同一列,即不移动到行首

`
`将光标移到行首(r 表示回车符,注意:回车符不包含换行符,因此光标仍在同一行),但不会删除任何内容

具体来说,在 xterm 中,我尝试了上面提到的回复,我发现删除该行并从头重新开始的唯一方法是序列(来自上面由@Stephan202 以及@vlp 和@mantal 发布的评论)`
`

在实现说明中,为了使其正常工作,例如在倒计时场景中,因为我没有`'
'`
在每个 的末尾使用换行符fprintf(),所以我每次都必须进行fflush()流式传输(为了给你一些上下文,我在 Linux 机器上使用 fork 启动了 xterm,没有重定向 stdout,我只是使用fdfile我位于伪终端地址上的非阻塞文件描述符写入缓冲的 FILE 指针,在我的情况下是/dev/pts/21):

fprintf(fdfile, "
T minus %d seconds...", i);
fflush(fdfile);

请注意,我使用了 33[2K 序列来删除行,然后使用`
回车符序列将光标重新定位到行首。我必须fflush()在每个序列后面都这样做fprintf(),因为末尾没有换行符'
'`。如果不需要 fflush() 就能得到相同的结果,则需要使用额外的序列来向上移动一行:

fprintf(fdfile, "
T minus %d seconds...
", i);

请注意,如果您要写入的行上方紧接着有内容,它将被第一个 fprintf() 覆盖。您必须在上面留出一行额外的内容,以便第一次向上移动一行:

i = 3;
fprintf(fdfile, "
Text to keep
");
fprintf(fdfile, "Text to erase****************************
");
while(i > 0) { // 3 second countdown
    fprintf(fdfile, "T
T minus %d seconds...
", i);
    i--;
    sleep(1);
}

解决方案 3:

您可以使用`
`(回车符)将光标返回到行首:

printf("hello");
printf("
bye");

这将在同一行打印bye。但它不会删除现有字符,而且由于bye比hello短,所以最终会得到byelo。要删除它,您可以将新打印加长以覆盖多余的字符:

printf("hello");
printf("
bye  ");

或者,先用几个空格擦除它,然后打印新的字符串:

printf("hello");
printf("
          ");
printf("
bye");

这将打印hello,然后转到行首并用空格覆盖它,然后再次回到开头并打印bye

解决方案 4:

您可以使用 b 删除该行

printf("hello");
int i;
for (i=0; i<80; i++)
{
  printf("");
}
printf("bye");

解决方案 5:

通常,当字符串末尾有 'r' 时,只会打印回车符而不打印任何换行符。如果您有以下内容:

printf("fooooo
");
printf("bar");

输出将是:

barooo

我可以建议的一件事(可能是一种解决方法)是使用一个以 NULL 结尾的固定大小字符串,该字符串初始化为所有空格字符,以 'r' 结尾(每次打印前),然后使用 strcpy 将字符串复制到其中(不带换行符),因此每次后续打印都会覆盖前一个字符串。类似这样的事情:

char str[MAX_LENGTH];        
// init str to all spaces, NULL terminated with character as '
'
strcpy(str, my_string);       // copy my_string into str
str[strlen(my_string)] = ' '; // erase null termination char
str[MAX_LENGTH - 1] = '
';
printf(str);

您可以进行错误检查,以使其my_string长度始终至少比短一str,但您已经了解了基本思想。

解决方案 6:

i遍历字符数组单词。 j跟踪单词长度。 " "在回退一行时删除单词。

#include<stdio.h>

int main()
{
    int i = 0, j = 0;

    char words[] = "Hello Bye";

    while(words[i]!='')
    {
        if(words[i] != ' ') {
            printf("%c", words[i]);
        fflush(stdout);
        }
        else {
            //system("ping -n 1 127.0.0.1>NUL");  //For Microsoft OS
            system("sleep 0.25");
            while(j-->0) {
                printf(" ");
            }
        }

        i++;
        j++;
    }

printf("
");                   
return 0;
}

解决方案 7:

该脚本针对您的示例进行了硬编码。

#include <stdio.h>

int main ()
{

    //write some input  
    fputs("hello
",stdout);

    //wait one second to change line above
    sleep(1);

    //remove line
    fputs("",stdout);
    rewind(stdout);

    //write new line
    fputs("bye
",stdout);

    return 0;
}

点击此处查看来源。

解决方案 8:

在 Windows 10 下,可以通过在当前控制台中激活 VT100 模式来使用 VT100 样式,以使用转义序列,如下所示:

#include <windows.h>
#include <iostream>

#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#define DISABLE_NEWLINE_AUTO_RETURN  0x0008

int main(){

  // enabling VT100 style in current console
  DWORD l_mode;
  HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
  GetConsoleMode(hStdout,&l_mode)
  SetConsoleMode( hStdout, l_mode |
            ENABLE_VIRTUAL_TERMINAL_PROCESSING |
            DISABLE_NEWLINE_AUTO_RETURN );

  // create a waiting loop with changing text every seconds
  while(true) {
    // erase current line and go to line begining 
    std::cout << "
";
    std::cout << "wait a second .";
    Sleep(1);
    std::cout << "
";
    std::cout << "wait a second ..";
    Sleep(1);
    std::cout << "
";
    std::cout << "wait a second ...";
    Sleep(1);
    std::cout << "
";
    std::cout << "wait a second ....";
 }

}

请参阅以下链接:windows VT100

解决方案 9:

printf("");

在此处输入图片描述

此处的ANSI Cursor Controls转义代码[#F代表 - 转到 # 行开头。

解决方案 10:

这里有一个简单的技巧可以使用,但是在打印之前需要做好准备,您必须将要打印的内容放在变量中,然后打印,这样您就会知道要删除字符串的长度。这是一个例子。

#include <iostream>
#include <string> //actually this thing is not nessasory in tdm-gcc

using namespace  std;

int main(){

//create string variable

string str="Starting count";

//loop for printing numbers

    for(int i =0;i<=50000;i++){

        //get previous string length and clear it from screen with backspace charactor

        cout << string(str.length(),'');

        //create string line

        str="Starting count " +to_string(i);

        //print the new line in same spot

        cout <<str ;
    }

}

解决方案 11:

使用此函数清除nC++ 中的行

void clear_line(int n) {
    std::string line_up = "";
    std::string line_clear = "
";
    for (int i = 0; i < n; ++i)
        std::cout << line_up << line_clear << std::flush;
}

解决方案 12:

刚刚发现这个旧线程,正在寻找某种转义序列来清空实际的行。

有趣的是,没有人想到(或者我错过了)printf 返回写入的字符数。因此,只需打印 'r' + printf 返回的空白字符数,您就会准确清空先前写入的文本。

int BlankBytes(int Bytes)
{
                char strBlankStr[16];

                sprintf(strBlankStr, "
%%%is
", Bytes);
                printf(strBlankStr,"");

                return 0;
}

int main(void)
{
                int iBytesWritten;
                double lfSomeDouble = 150.0;

                iBytesWritten = printf("test text %lf", lfSomeDouble);

                BlankBytes(iBytesWritten);

                return 0;
}

由于我无法使用 VT100,看来我必须坚持使用这个解决方案

解决方案 13:

echo -e "helloc" ;sleep 1 ; echo -e "
bye  "

上述命令将执行的操作:

  1. 它将打印 hello 并且光标将停留在“o”处(使用 c)

  2. 然后它将等待 1 秒(睡眠 1)

  3. 然后它将用 bye 替换 hello。(使用 r)

NOTE : Using ";", We can run multiple command in a single go.

解决方案 14:

对我来说,此代码适用于 Tera Term VT 控制台上带有 arduino 的串行控制台窗口:

SEROUT.print("e[A
e[2K");
SEROUT.print('>');

我使用 '>' 因为在我的控制台命令中我在 '>' 后输入命令

解决方案 15:

其他人已经回答了 OP 的问题。对于那些想知道为什么回车符在 Linux 机器上的行为如此的人,这里有一个答案 -

回车符的行为似乎与平台相关。

来自 C11 标准的“5.2.2 字符显示语义”部分:

r(回车)将活动位置移动到当前行的起始位置。

摘自 POSIX 标准的“3.86 回车符 (<carriage-return>)”一节 ( https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html ):

输出流中的字符,表示打印应从出现回车符的同一物理行的开头开始。它是 C 语言中由 'r' 指定的字符。尚不清楚此字符是否是系统传输到输出设备以完成移动到行首的准确序列。

它没有说明回车符是否应该删除(=> 用 NUL 字符填充)整行。我的猜测是它不应该删除。

但是,在我的 Linux 机器上(在 x86_64 和 ARM32 上都试过),我发现回车符将光标移动到当前行的开头,并且还在行中填充了 '0' 字符(NUL 字符)。为了注意到这些 NUL 字符,您可能必须直接从代码中调用 write 系统调用,而不是通过 glibc printf 调用。

我们以下面的代码片段为例:

printf(&quot;hello&quot;);
printf(&quot;
bye&quot;);

在 beaglebone black (32 位 ARM) bash 终端上构建并运行此程序:

ubuntu@arm:~$ ./a.out 
byeubuntu@arm:~$ 

写入系统调用时的 strace 输出:

bye)               = 9 9hello
+++ exited with 4 +++
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用