分裂句子和放置在向量中

时间:2015-03-04 06:39:07

标签: c++

我从教授那里得到了一个代码,它带有多行输入。我目前正在更改当前任务的代码,我遇到了一个问题。代码用于获取输入字符串并将它们分成句点中的句子并将这些字符串放入向量中。

vector<string> words;
string getInput() {
  string s = ""; // string to return
  bool cont = true; // loop control.. continue is true
  while (cont){     // while continue
    string l;       // string to hold a line
    cin >> l;       // get line
    char lastChar = l.at(l.size()-1);
    if(lastChar=='.') {
        l = l.substr(0, l.size()-1);
        if(l.size()>0){
            words.push_back(s);
            s = "";
        }
    }
    if (lastChar==';') {     // use ';' to stop input
        l = l.substr(0, l.size()-1);
        if (l.size()>0) 
          s = s + " " + l;
        cont = false; // set loop control to stop
      }

    else
      s = s + " " + l; // add line to string to return
                       // add a blank space to prevent
                       //   making a new word from last
                       //   word in string and first word
                       //   in line
  }
  return s;
}

int main()
{
  cout << "Input something: ";
  string s = getInput();
  cout << "Your input: " << s << "\n" << endl;
  for(int i=0; i<words.size(); i++){
    cout << words[i] << "\n";
  }
}

代码将字符串放入向量中,但是接受句子的最后一个单词并将其附加到下一个字符串,我似乎无法理解为什么。

3 个答案:

答案 0 :(得分:1)

这一行

s = s + " " + l;

将始终执行,输入结束除外,即使最后一个字符是&#39;。&#39;。您很可能在两个else - s之间错过if

答案 1 :(得分:0)

你有:

string l;       // string to hold a line
cin >> l;       // get line

除非整行包含非空白字符,否则最后一行不会读取一行。要阅读一行文字,请使用:

std::getline(std::cin, l);

由于您尚未发布任何样本输入,因此很难说这是否会使您的代码绊倒。

答案 2 :(得分:0)

我至少认为做这项工作的方式有所不同。现在,你一次只读一个单词,然后将这些单词重新组合起来,直到你进入一段时间。

一种可能的替代方法是使用std::getline读取输入,直到达到句点,然后立即将整个字符串放入向量中。以这种方式完成工作的代码可能如下所示:

#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <iterator>

int main() {
    std::vector<std::string> s;

    std::string temp;
    while (std::getline(std::cin, temp, '.'))
        s.push_back(temp);

    std::transform(s.begin(), s.end(), 
        std::ostream_iterator<std::string>(std::cout, ".\n"), 
        [](std::string const &s) { return s.substr(s.find_first_not_of(" \t\n")); });
}

在某种情况下,这种行为会有所不同 - 如果你的某个时间段其他而不是单词的末尾,原始代码将忽略该句号(不会将其视为结束)一句话)但这会。这会产生影响的显而易见的地方是输入包含一个带小数点的数字(例如1.234),这会在小数点处中断,因此它会将1视为一个句子的结尾,234作为另一个句子的开头。但是,如果您不需要处理这种类型的输入,则可以大大简化代码。

如果句子可能包含小数点,那么我可能会更像这样编写代码:

#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <iterator>

class sentence {
    std::string data;
public:
    friend std::istream &operator>>(std::istream &is, sentence &s) {
        std::string temp, word;
        while (is >> word) {
            temp += word + ' ';
            if (word.back() == '.')
                break;
        }
        s.data = temp;
        return is;
    }
    operator std::string() const { return data; }
};

int main() {
    std::copy(std::istream_iterator<sentence>(std::cin),
        std::istream_iterator<sentence>(),
        std::ostream_iterator<std::string>(std::cout, "\n"));
}

虽然有点长且更复杂,但至少在我看来它仍然(相当)比问题中的代码简单。我猜它在某种程度上是不同的 - 它通过检测输入结束来检测输入的结束,而不是依赖于输入来包含一个特殊的分隔符来标记输入的结束。如果您以交互方式运行它,通常需要使用特殊的组合键来表示输入结束(例如,Linux / Unix上的 Ctrl + D ,或Windows上的 F6

在任何情况下,可能值得考虑这段代码与问题中的代码之间的根本区别:这将一个句子定义为类型,其中原始代码只是将所有内容都保留为字符串,并且操纵字符串。这为句子定义operator>>,从我们想要读取的流中读取句子。这为我们提供了一种可以作为对象操作的类型。由于它在其他方面类似于字符串,因此我们提供了对字符串的转换,因此一旦您从流中读取了一个字符串,您就可以将其视为字符串。完成后,我们可以(例如)使用标准算法从标准输入读取句子,并将它们写入标准输出,每个输出后用一个新行分隔它们。