如何从标准输入读取输入,直到按下空格或制表符?

3

我需要从标准输入中读取输入,直到按下空格或TAB键。

最终,我需要将输入保存在std::string对象中。


由于输入通常是行缓冲的,我认为这并不容易实现。 - Xeo
1
如果输入是交互式的,终端通常不会发送内容,直到完整的一行被键入(输入在用户按下“回车”键后发送)。如果你期望能够随意输入并且希望程序在每个空格或制表符字符处做出反应,那么你可能会有些惊讶。 - André Caron
1
C++没有“按键”的概念。您需要一个特定于平台的终端处理库。尝试使用ncurses - Kerrek SB
@Kerrek SB - 我没有表达清楚。我的意思是在发现TAB或空格之前,而不是在键入之前。如果我从文件中读取,我希望字符串仅包含第一个单词,直到制表符/空格。 - AAaa
8个回答

4
#include <iostream>
#include <string>

int main()
{
    std::string result;
    std::cin >> std::noskipws; //don't skip whitespaces
    char c;
    while (std::cin >> c)
    {
        if(c == '\t' || c == ' ')
             break;
        result.push_back(c);
    }

}

我尝试运行它,但它一直在获取空格和TAB之后的输入。最终只有空格之前的字符被存储在结果中(这很好),但由于某种原因,只有当我按回车键时,输入窗口才会关闭。 - AAaa
2
@AAaa:为了让输入起作用,最终必须按ENTER键。在这种情况下,您的字符串将只包含第一个制表符或空格之前的字符。实际上没有标准的C++方法可以检测到按键。 - Armen Tsirunyan
4
直到用户按下回车键,程序才能接收输入,因为终端程序在按下回车键之前不会发送输入。 这个“特性”允许终端在将输入发送给程序之前实现编辑(例如按下退格键并更改输入)。 - André Caron

3

由于制表符被视为空格,因此您要求从流中提取第一个标记。在C++中,这非常容易,因为标记提取已经是>>运算符的默认行为:

#include <iostream>
#include <string>

int main()
{
    std::string token;

    if (!(std::cin >> token)) { /* error */ return 1; }

    // now you have the first token in "token".
}

(该错误只会在晦涩的情况下发生,例如当输入文件描述符在程序启动时已经关闭时。)

2
你可以使用getch()getchar()来逐个读取每个字符,然后手动处理输入,以便在按下空格或制表符时结束输入。

2
getch 是特定于平台的; 在大多数平台上不存在。getchar 相当于 std::cin.get(),正如原始帖子中的一些评论所指出的那样,大多数系统在按下回车键之前不会返回任何内容。 - James Kanze

1

这应该可以完成工作:

#include <stdio.h>

int main ()
{
  char c;
  do {
    c=getchar();
    /** Your code here **/
  } while ((c != ' ') && (c != '\t'));
  return 0;
}

我最终需要得到一个std::string,我能用你的示例做到吗? - AAaa
在循环之前创建一个空的 std::string,并附加每个字符(您可以使用重载的 += 运算符)。 - nikolas
只需将字符添加到字符串中,例如 str.push_back(c) - Dr G
谢谢。但是和我对亚美尔回答的评论一样,由于某种原因,在输入空格或制表符后,输入窗口没有关闭。我知道之后输入的内容没有被读取,因为我检查了结果并且得到了我需要的内容,但是输入窗口本身没有关闭。只有在按下回车键后才会关闭。 - AAaa

1

您可以使用std::cin在任何指定字符处停止读取。

char temp[100];
std::cin.getline(temp, 100, '\t');

我不知道你是否可以轻松地让它与两个字符一起工作。


你不能这样做,但如果你真的需要这样的功能,你可以编写自己的 std::getline() 版本,它接受一个谓词作为第三个参数,并针对其进行测试,而不是换行符。 - André Caron

1

看起来,使用scanf("%[^\t ]", buffer)解决这个问题确实更容易。如果您想使用C++ IOStreams进行操作,我认为最好的选择是安装一个带有修改过的std::ctype<char> facet的std::locale,该facet使用修改后的空格解释方式,然后读取一个std::string(例如,请参见我为类似问题提供的this answer)。无论您是使用C还是C++方法,如果要在输入标准输入时查找空格或制表符而不是在整行输入时查找,您可能需要关闭标准输入上的行缓冲。


0

使用scanf来实现:

一个简单的代码:

#include<iostream>
#include<stdio.h>
int main()
{
        char t[1000]={'\0'};
        scanf("%[^\t ]",t);
        printf("%s",t);
        std::string mains(t);
        return 1;

}

0
简单的答案是你不能。实际上,你提出的问题表明你不理解istream输入:在istream中没有“pressed”这样的东西,因为无法保证输入来自键盘。
你可能需要的是cursesncurses,它们可以理解键盘输入、控制台输出和其他内容。

加油,詹姆斯!我们都知道你可以关闭行缓冲(至少在POSIX系统上),即使使用std::cin也可以。当然,我们可能不知道它是否连接到键盘,但我们可能不在意:只需调用系统调用,不要对其结果过于挑剔。 - Dietmar Kühl
@DietmarKühl 当然有一些依赖于系统的解决方案,例如 curses。问题是它们只能在特定的系统上运行。据我所知,在 Windows 下,规避行缓冲的唯一方法是使用不同的系统调用。(但是,我对 Windows 的了解不是很深入,可能会有我所不知道的东西。) - James Kanze

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接