如何在C ++中使用istream&,string&和getline读取复杂的输入?

时间:2018-11-19 16:44:04

标签: c++

我对C ++还是很陌生,所以如果这不是一个好问题,我深表歉意,但是在理解如何使用istream方面我确实需要帮助。

我必须创建一个项目,该项目需要将可能在一行或多个行上的多个输入量传递给一个矢量(这只是该项目的一部分,我想尝试其余的输入我自己的),例如,如果我要输入...

>> aaa    bb
>> ccccc
>> ddd fff  eeeee

使用“ aaa”,“ bb”,“ ccccc”,“ ddd”,“ fff”,“ eeeee”作为字符串的向量

输入可以是char或字符串,并且在按下回车键时程序会停止要求输入。

我知道getline()获得了一行输入,我可能可以使用while循环尝试获取诸如...的输入(如果我错了,请纠正我)

while(!string.empty())
     getline(cin, string);

但是,我并没有真正理解istream,并且我的课程没有遍历指针也无济于事,所以我不知道如何使用istream&或string&将其传递给向量。在项目描述中,它说不使用stringstream,而是使用getline(istream&,string&)中的功能。任何人都可以对如何使用getline(istream&,string&)创建函数,然后如何在主函数中使用它进行详细的解释吗?

有什么帮助!

2 个答案:

答案 0 :(得分:1)

您可以输入第一列的值,然后基于该值调用函数:

void Process_Value_1(std::istream& input, std::string& value);
void Process_Value_2(std::istream& input, std::string& value);

int main()
{
  // ...
  std::string first_value;
  while (input_file >> first_value)
  {
     if (first_value == "aaa")
     {
         Process_Value_1(input_file, first_value);
     }
     else if (first_value = "ccc")
     {
         Process_Value_2(input_file, first_value);
     }
     //...
  }
  return 0;
}

一个示例函数可以是:

void Process_Value_1(std::istream& input, std::string& value)
{
  std::string b;
  input >> b;
  std::cout << value << "\t" << b << endl;
  input.ignore(1000, '\n'); // Ignore until newline.
}

还有其他方法可以执行此过程,例如使用函数指针表和std::map

答案 1 :(得分:1)

您已经走对了路;完全是这样,您必须用一些虚拟对象预填充字符串才能完全进入while循环。更优雅:

std::string line;
do
{
    std::getline(std::cin, line);
}
while(!line.empty());

如果用户输入一个空行,这应该已经可以逐行(但是可能在一行上有多个单词!)并完成技巧的读取(请注意,空格和换行符不会被这样识别!)

但是,如果流中有任何错误,您将陷入无限循环中,一次又一次地处理先前的输入。因此最好也检查流状态:

if(!std::getline(std::cin, line))
{
    // this is some sample error handling - do whatever you consider appropriate...
    std::cerr << "error reading from console" << std::endl;
    return -1;
}

由于一行上可能有多个单词,因此您必须将它们分开。 有多种方法,一种很简单的方法是使用std::istringstream –您会发现它与您可能习惯使用std::cin的样子相似: < / p>

    std::istringstream s(line);
    std::string word;
    while(s >> word)
    {
        // append to vector...
    }

请注意,使用operator>>会忽略前导空格,并在第一个尾随空格(或流的末尾,如果到达)之后停止,因此您不必显式处理。 / s>

好的,您不允许使用std::stringstream(好吧,我使用的是std:: i stringstream,但我想这个小区别并没有计数,是吗?)。更改有一点点,它变得更加复杂,另一方面,我们可以自己决定什么算作单词,什么算作分隔符...我们可以将标点符号视为分隔符,就像空格一样,但是允许数字成为单词的一部分,所以我们接受e。 G。 ab.7c d"ab", "7c", "d"

auto begin = line.begin();
auto end = begin;
while(end != line.end()) // iterate over each character
{
    if(std::isalnum(static_cast<unsigned char>(*end)))
    {
        // we are inside a word; don't touch begin to remember where
        // the word started
        ++end;
    }
    else
    {
        // non-alpha-numeric character! 
        if(end != begin)
        {
            // we discovered a word already
            // (i. e. we did not move begin together with end)
            words.emplace_back(begin, end);
            // ('words' being your std::vector<std::string> to place the input into) 
        }
        ++end;
        begin = end; // skip whatever we had already
    }
}
// corner case: a line might end with a word NOT followed by whitespace
// this isn't covered within the loop, so we need to add another check:
if(end != begin)
{
    words.emplace_back(begin, end);
}

对于什么是分隔符和什么算作单词(例如std::isalpha(...) || *end == '_',以便将下划线检测为单词的一部分,而数字不是),适应不同的解释应该不太困难。您可能会发现很多helper functions有用...