如何操作标准输出?



例如,当使用GitHub CLI时,它们提示你如下:

Do something? (Y/n)

,如果你要输入n并按'Enter',那么输出将变为:

Do something? No
'Next line's content'

我想在我的程序中做类似的事情。

在我的用例中,它看起来像:
Row 1: 1 2 3
Row 2: 4 5 6
Row 3: 7 8 9
Row 4:

,其中用户输入整数,按'Enter',现在在Row 4:上。

当用户按下'Enter'时,我希望它转换成:

Row 1: 1 2 3
Row 2: 4 5 6
Row 3: 7 8 9
Row 4: N/A

,或者最好是:

Row 1: 1 2 3
Row 2: 4 5 6
Row 3: 7 8 9

,但我不确定如何做到这一点,因为用户按"Enter"会把std::out放在新的行,如果我要打印出N/A,它看起来像:

Row 1: 1 2 3
Row 2: 4 5 6
Row 3: 7 8 9
Row 4:
N/A

终端应用程序通过向终端发送特殊的控制字符来实现这一点(这是一个非常老派的API!)像ncurses这样的库和像tput这样的外部工具可以为你制作奥术咒语,但你自己做并不难。

在这种情况下,一旦用户按下输入,您需要将光标移回到上一行的开头,清除该行的其余部分,并写入您想要的内容。

#define ESC_PREV_LINE "e[F"
#define ESC_CLEAR_TO_END "e[K"
std::cerr << "Row 4: " << std::flush; // traditionally, interactive prompts appear on stderr! this makes it easy to separate the "real" output of a program from the interactive part to e.g. save in a file
// read input...
if(need_to_rewrite_input) {
std::cerr << ESC_PREV_LINE ESC_CLEAR_TO_END "Row 4: 7 8 9n";
}

你可能想在程序开始时检查cerr是否真的指向终端,如果不是,要么使用回退行为,要么直接退出。

一个选择是使用像ncurses这样的库。例如,如果您想覆盖光标前面的多行输出,这一点尤其重要。

如果您正在寻找更基本的东西(例如,仅影响最后一行的输出,并且没有太多的错误检查,并且不依赖于通常特定于设备的转义码),您可以执行以下操作:

const std::string yesno = "(Y/n)"
char input;
std::cout << "Do something? " << yesno << " ";
std::cin >> input;
if (std::toupper(input) == 'Y')
{
for (std::size_t i = 0; i < yesno.length() + 2; ++i)
std::cout << "b b";
std::cout << 'Y';
std::cout << std::endl;
}
// code that produces next line of output

循环在最后一行备份一个覆盖字符,每次一个。循环中的神奇数字2来自于需要覆盖空格字符和用户输入的单个字符。

上面的缺点是它假设用户在按回车键之前只输入一个字符。没有办法阻止用户做一些不同的事情(例如,用户可能会在按回车键之前愉快地输入YYYY)。

为了解决这个问题,我们可以这样做

如果你想放松这个假设,下面是可能的

const std::string yesno = "(Y/n)"
std::string input;
std::cout << "Do something? " << yesno << " ";
std::getline(std::cin, input);
if (input.length() > 0 && std::toupper(input[0]) == 'Y')
{
for (std::size_t i = 0; i < yesno.length() + input.length() + 1; ++i)
std::cout << "b b";
std::cout << 'Y';
std::cout << std::endl;
}
// code that produces next line of output

这将处理用户在回车键之前输入YNYN,通过只检查输入的第一个字符,忽略(并覆盖)其余的字符。

以上两个都假设输出一个空格字符将覆盖光标位置的字符)。但是大多数现代终端或控制台(窗口系统中的硬件设备或模拟器)的默认设置与该假设一致。有一些旧设备(大部分已经过时了,现在很少在历史展览或博物馆外看到),这种假设是不成立的[护士通常不会发现,更不用说正确处理这些设备了]。

另一个假设是终端宽度超过用户输入的长度。因此,如果终端/窗口宽度为80个字符,则假定用户在按回车键之前不会输入80个或更多字符。

相关内容

  • 没有找到相关文章

最新更新