【问题标题】:problems with dividing the words while parsing the formatted input解析格式化输入时分割单词的问题
【发布时间】:2013-09-04 14:32:14
【问题描述】:
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <string>
int main(int argc, char *argv[])
{
    std::vector<std::string> vec;
    std::string line;
    std::ifstream in(argv[1]);
    while(!in.eof()) {
        std::getline(in,line);
        vec.push_back(line);
    }
    std::istringstream is;
    line = "";
    for(auto a:vec) {
        for(auto i = a.begin(); i != a.end(); i++) {
            if(!(isspace(*i) | ispunct(*i)))
                line += *i;
            else {
                is.str(line);
                std::cout << is.str() << std::endl;
                line = "";
            }
        }
    }
    std::cout << is.str() << std::endl;
    return 0;
}

我编写了一个程序,它获取一个文件并将每一行放入一个字符串向量中。然后从元素中一次读取一个单词。

当我从向量中读取时,我无法指定新行。我的输出连接了一行的结尾和下一行的开头。如何指定有新行?

我正在阅读的文件内容:

Math 3 2
Math 4 3
Math 5 4
Phys 3 1
Math 3 1
Comp 3 2

我得到的输出:

Math
3
2Math
4
3Math
5
4Phys
3
1Math
3
1Comp
3
3

编辑::

为了澄清,向量元素的构造是正确的。如果我从 for(auto a:vec) 打印一个 in,它会像文件一样逐行给我。当我尝试从向量中的每个字符构建单词时。我在问我该怎么做才能指定有一个新行,以便

line += a[i] 

当它到达一行的末尾时不会继续添加到行。

【问题讨论】:

  • 附注:我个人更喜欢使用传统的for 循环而不是for(auto a:vec) 以避免使用if(!(isspace(*i) | ispunct(*i))) line += *i; 之类的代码:)
  • 我打算走另一条路:for (auto c:a) 这里非常适合。
  • 为了消除另一个冗余,你可以直接吐line,不需要构造一个stringstream。
  • 同志:std::getline 不提供行终止符。提示 #2:在什么情况下你可以从a 中读取一个字符而不吐出换行符?提示 #3:尝试在每个输入行的末尾添加一个空格,看看这里发生了什么......
  • for(auto c:a) 打印每个字符。当有空格或标点符号或换行符时,我仍然必须指定不要附加到字符串,我无法弄清楚如何指定。

标签: c++ string parsing io formatting


【解决方案1】:

别这样

while (!in.eof()) { ... }

它不会像你期望的那样工作。

改为

while (std::getline(...)) { ... }

这是因为eof 标志在您实际尝试读取文件末尾时才设置。这意味着您将循环一次到多次,尝试读取不存在的行,然后将其添加到向量中。


还有另一种在空间边界上分隔“单词”的方法,使用std::istringstream 和普通输入运算符&gt;&gt;

std::istringstream is{a};

std::string word;
while (is >> word)
{
    // Do something with `word`
}

【讨论】:

  • while (std::getline(in, line)) { 循环中,也可以使用line.empty() 来确保不读取空行:)
  • 让我澄清一下。构造向量后的输出为我提供了正确的向量元素。这是我遇到麻烦的第二部分。当我从字符构建单词时。
  • 值得注意的是,std::istringstream is{a} 是 C++11 语法。
  • @Comrade 我刚刚用另一种在空格上分割一行的方式更新了我的答案。
  • @JoachimPileborg。我很感激你的回答。我试过这个并且它有效,但它是一个替代答案。有没有一种简单的方法可以使用诸如 ispunct() 之类的内置函数来识别是否有新行?
【解决方案2】:

这里的实际问题是代码逻辑错误。这是您在打印输出时所做的伪代码:

for every line:
    for every character in the line:
        if it is alphanumerical character
            then add it to the word
        else
            print the so-far built word

现在看Math 4 3行~>在打印出单词“4”之后,这段代码将字符'3'添加到行中但不将其打印为单词,因此3是开头下一行的单词。

另请注意,您的代码远比必要的复杂。它可能看起来像这样:

std::string word;
for (size_t i = 0; i < vec.size(); ++i) {
    std::istringstream lineStream(vec[i]);
    while (lineStream >> word)
        std::cout << word << std::endl;
}

但如果您想保留原始代码,您可以采取以下措施来解决此问题:

line = "";
for(auto a:vec) {
    for(auto i = a.begin(); i != a.end(); i++) {
        if (isalnum(*i))
            line += *i;
        else {
            std::cout << line << std::endl;
            line = "";
        }
    }

    // before we start processing the next element...
    // in case there's another line to be printed:
    if (!line.empty()) {
        // print the line and reset the variable:
        std::cout << line << std::endl;
        line = "";
    }
}

【讨论】:

  • 是的,代码缺少换行符。我在问什么是指定有新行的方法。
  • 是的,我知道有另一种方法可以做到这一点,但我所追求的是当我将字符添加到字符串时如何指定何时获得新行。我以前遇到过这个问题,这就是我想知道的。
  • @Comrade:我认为您想保留原始代码。如果我理解正确,请检查我的答案的编辑。
  • 毫无疑问,这是可行的,并且在原始代码的情况下这是一个很好的方法。有没有办法使用逻辑和像'\n'这样的字符来指定行尾?
【解决方案3】:

您也可以使用这样的向量逐行读取;

向量定义;

    struct VectorName {
       std::string str;
       float num1;
       float num2;
};

std::vector <VectorName> smthVector_;

函数的使用

   VectorName vector;
   std::string str;
   char buf_1[50];
   while(std::getline(in, str))
   {
       if(sscanf(str.c_str(), "%s %f %f", buf_1, &vector.num1, &vector.num2) == 3)
       {
           vector.str = buf_1;
           smthVector_push_back(vector);
       }
        else
            std::cout << "No param in string  " << str << std::endl;
   }

【讨论】:

    猜你喜欢
    • 2021-01-05
    • 1970-01-01
    • 2012-10-14
    • 1970-01-01
    • 1970-01-01
    • 2015-05-02
    • 1970-01-01
    • 2018-08-02
    • 1970-01-01
    相关资源
    最近更新 更多