Стереть текущую строку печатной консоли
9 ответов
можно использовать VT100 коды эвакуации. Большинство терминалов, включая xterm, знают VT100. Для стирания строки это ^[[2K
. В C это дает:
printf("%c[2K", 27);
можно использовать \r
(возврат каретки) для возврата курсора в начало строки:
printf("hello");
printf("\rbye");
выводит пока на той же строке. Он не будет стирать существующие символы, хотя, и потому что пока меньше, чем привет, вы будете в конечном итоге с byelo. Чтобы стереть его, вы можете сделать новую печать длиннее, чтобы перезаписать дополнительные символы:
printf("hello");
printf("\rbye ");
или, сначала удалите его с помощью несколько пробелов, затем распечатайте новую строку:
printf("hello");
printf("\r ");
printf("\rbye");
это будет печатать привет, затем перейдите в начало строки и перепишите ее пробелами, затем снова вернитесь к началу и напечатайте пока.
некоторые полезные тонкости...
[2K
стирает всю строку, на которой в данный момент находится курсор
3[A
перемещает курсор вверх на одну строку, но в тот же столбец т. е. не до начала строки
\r
приводит курсор к началу строки (r для перемотки назад), но не стереть что-нибудь
в xterm конкретно, я попробовал ответы, упомянутые выше, и единственный способ, который я нашел чтобы стереть строку и начать снова в начале, это последовательность (из комментария выше, опубликованного @Stephan202, а также @vlp и @mantal) [2K\r
в примечании к реализации, чтобы заставить его работать правильно, например, в сценарии обратного отсчета, так как я не использовал новый символ строки '\n'
в конце каждого fprintf()
, поэтому мне пришлось fflush()
поток каждый раз (чтобы дать вам некоторый контекст, я начал xterm с помощью вилки на машине linux без перенаправления stdout, я просто запись в буферизованный файл указателя fdfile
с неблокирующим файловым дескриптором я сидел на псевдо-терминальном адресе, который в моем случае был /dev/pts/21
):
fprintf(fdfile, "[2K\rT minus %d seconds...", i);
fflush(fdfile);
обратите внимание, что я использовал последовательность \33[2K для стирания строки, за которой следует \r
перемотать последовательность, чтобы переместить курсор в начале строки. Мне пришлось fflush()
после каждого fprintf()
потому что у меня нет нового символа строки в конце '\n'
. Тот же результат без необходимости fflush () требуется дополнительная последовательность, чтобы подняться вверх по строке:
fprintf(fdfile, "3[A[2K\rT minus %d seconds...\n", i);
обратите внимание, что если у вас есть что-то в строке непосредственно над строкой, на которой вы хотите писать, это будет переписано с первым fprintf(). Вам нужно будет оставить дополнительную строку выше, чтобы разрешить первое движение вверх по одной строке:
i = 3;
fprintf(fdfile, "\nText to keep\n");
fprintf(fdfile, "Text to erase****************************\n");
while(i > 0) { // 3 second countdown
fprintf(fdfile, "3[A[2KT\rT minus %d seconds...\n", i);
i--;
sleep(1);
}
обычно, когда у вас есть "\r " в конце строки, только возврат каретки печатается без какой-либо новой строки. Если у вас есть следующее:
printf("fooooo\r");
printf("bar");
выход будет:
barooo
одна вещь, которую я могу предложить (возможно, обходной путь), - это иметь строку фиксированного размера с нулевым завершением, которая инициализируется для всех символов пробела, заканчиваясь на "\r" (каждый раз перед печатью), а затем использовать strcpy для копирования вашей строки в нее (без новой строки), поэтому каждый последующий print перезапишет предыдущую строку. Что-то вроде этого:--6-->
char str[MAX_LENGTH];
// init str to all spaces, NULL terminated with character as '\r'
strcpy(str, my_string); // copy my_string into str
str[strlen(my_string)] = ' '; // erase null termination char
str[MAX_LENGTH - 1] = '\r';
printf(str);
вы можете сделать проверку ошибок, так что my_string
всегда по крайней мере один меньше в длину, чем str
, но вы получите основную идею.
вы можете удалить строку, используя \b
printf("hello");
int i;
for (i=0; i<80; i++)
{
printf("\b");
}
printf("bye");
i
перебирает слова типа char массив. j
отслеживает длину слова. "\b \b"
стирает слово во время резервного копирования по линии.
#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("\b \b");
}
}
i++;
j++;
}
printf("\n");
return 0;
}
этот скрипт жестко закодирован для вашего примера.
#include <stdio.h>
int main ()
{
//write some input
fputs("hello\n",stdout);
//wait one second to change line above
sleep(1);
//remove line
fputs("3[A3[2K",stdout);
rewind(stdout);
//write new line
fputs("bye\n",stdout);
return 0;
}
Нажмите здесь источник.
есть простой трюк, который вы можете работать здесь, но он нуждается в подготовке перед печатью, вы должны поместить то, что вы хотите напечатать в переменной, а затем распечатать, чтобы вы знали длину, чтобы удалить строку.вот пример.
#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(),'\b');
//create string line
str="Starting count " +to_string(i);
//print the new line in same spot
cout <<str ;
}
}
просто нашел этот старый поток, ища какую-то escape-последовательность, чтобы очистить фактическую строку.
забавно, что никто не пришел к идее (или я ее пропустил), что printf возвращает количество написанных символов. Поэтому просто распечатайте "\r " + столько пустых символов, сколько printf, и вы точно очистите ранее написанный текст.
int BlankBytes(int Bytes)
{
char strBlankStr[16];
sprintf(strBlankStr, "\r%%%is\r", 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, кажется, я должен придерживаться этого решения