【问题标题】:Losing random characters with istringstream使用 istringstream 丢失随机字符
【发布时间】:2013-05-03 21:49:13
【问题描述】:

我正在将文本文件的行读入变量 myline,然后尝试使用 istringstream 标记这些行。但是,似乎我正在丢失原始文本文件字符串中的随机字符。

cout<< myline << buff << flush; //print original text file line
istringstream iss(myline);
string sub;
while (iss >> sub) {
cout << "[" << sub << "]" << endl;
} 

如果您查看我的输出,您会发现我从文本文件中获得了正确的字符串,但是当我使用 istringstream 然后打印各个标记(在 [] 括号内看到)时,一些标记被过早截断.

#include <iostream>
[#include]
[<iostream]
#include <sstream>
[#include]
[<sstream>]
using namespace std;
[using]
[namespace]
[st]

int main()
[int]
[main(]
{
    string str("   SOME  LONG    STRING\twith\nSPACES    ");
[string]
[str("]
[SOME]
[LONG]
[STRING\twith\nSPACES]

    istringstream iss(str);
[istringstream]
[iss(str);]

    string s;
[strin]
    while (iss >> s) {
[while]
[(iss]
[>>]
        cout << "[" << s << "]" << endl;
[cout]
[<<]
["["]
[<<]
[s]
[<<]
["]"]
[<<]
[e]
    }
    return 0;
[retur]
}

有人知道我做错了什么吗?提前致谢!

编辑:这是可以完全编译的代码版本。您可以使用任何文本文件运行它

#include <cstring>
#include <cstdio>
#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <vector>
#include <algorithm>
#include <iterator>

using namespace std;

class MyFileReader {

public:
    //constructor
    MyFileReader(const char* p);

    //destructor
    ~MyFileReader();

    //getLine()
    int getLine(char *buffer, int size);

    //getCurrentLineNumber()
    int getCurrentLineNumber();

    void tokenizeLine(vector<string>& vec);

    FILE * pFile;

};

    //constructor
    MyFileReader::MyFileReader(const char* p) {
        pFile = fopen(p, "r");
    }

    //destructor
    MyFileReader::~MyFileReader() {
        fclose(pFile);
    }

    //getLine()
    int MyFileReader::getLine(char *buffer, int size){
        char *out = fgets(buffer, size, pFile);
        if (out==NULL) {
            return -1;
        }
        char *pch = strpbrk(out,"\n");
        if (pch != NULL) {
            return 1;
        }
        else {
            return 0;
        }

    }

    int MyFileReader::getCurrentLineNumber() {
        static int mynumber=2;
        return mynumber++;
    }

    //tokenizeLine
    void MyFileReader::tokenizeLine(vector<string>& vec) {
        string myline("");
        char buff[10];
        while (1) {
            int result = getLine(buff, sizeof(buff));
            if (result == -1 ) {
                if (myline.length() > 0) 
                    cout << myline << flush;
            break;
            }
            else if (result == 0) {
                myline += buff;
            }
            else if (result == 1) {
                cout<< myline << buff << flush;
                istringstream iss(myline);
                string sub;
                while (iss >> sub) {
                    cout << "[" << sub << "]" << endl;
                } 
                myline = "";
            }
            else {
                printf("PANIC");
            }
            }
            return;
        }

    int main(int argc, char **argv) {
    vector<string> v;

    const char *filename = argv[1];
    MyFileReader f(filename);
    f.tokenizeLine(v);
    return 0;

    }

为了生成上面的输出,我运行它:

#include <iostream>
#include <sstream>
using namespace std;

int main()
{
    string str("   SOME  LONG    STRING\twith\nSPACES    ");

    istringstream iss(str);

    string s;
    while (iss >> s) {
        cout << "[" << s << "]" << endl;
    }
    return 0;
}

【问题讨论】:

  • SSCCE + 原始输入会很好
  • ..error...cannot..reproduce...need...更多你的代码...
  • 用可编译代码@DyP编辑

标签: c++ c++11


【解决方案1】:

错误就在这里:

else if (result == 1) {
            cout<< myline << buff << flush;
            istringstream iss(myline);
            string sub;
            while (iss >> sub) {
                cout << "[" << sub << "]" << endl;
            } 
            myline = "";
        }

如果result == 1,则意味着buff包含 \n,并不意味着它包含\n。 IE。如果缓冲区包含\n,则删除它。因此,如果该行恰好有 n*10 (sizeof buffer) 个字符,则您的代码可以工作,否则,行的最后一个字符不会复制到 myline 而是删除。

快速解决办法是:

    else if (result == 1) {
            myline += buff; // copy the rest of the line into `myline`
            cout<< myline << flush; // buff now is part of myline
            istringstream iss(myline);
            string sub;
            while (iss >> sub) {
                cout << "[" << sub << "]" << endl;
            } 
            myline = "";
        }

尽管您可能想考虑从缓冲区中删除 \n,例如:

int MyFileReader::getLine(char *buffer, int size){
    char *out = fgets(buffer, size, pFile);
    if (out==NULL) {
        return -1;
    }
    //char *pch = strpbrk(out,"\n");
    char *pch = strchr(out,'\n'); // no need to search for a string
    if (pch != NULL) {
        *pch = '\0'; // drop the '\n'
        return 1;
    }
    else {
        return 0;
    }

}

不过,您必须将 cout&lt;&lt; myline &lt;&lt; flush; 更改为 cout&lt;&lt; myline &lt;&lt; endl;


除了这个错误,请考虑使用ifstream

#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;

int main()
{
    ifstream file("test.txt");
    if(!file)
    {
        /* error */
    }else
    {
        string line;
        while(getline(file, line))
        {
            istringstream iss(line);

            string s;
            while (iss >> s) {
                cout << "[" << s << "]" << endl;
            }
        }
    }
}

【讨论】:

  • 谢谢!我没有考虑缓冲区的其余部分,这很有意义。
【解决方案2】:

您的行缓冲区只有 10 个字节长。这还不够长,无法容纳一整行。

void MyFileReader::tokenizeLine(vector<string>& vec) {
        string myline("");
        char buff[10];// this is too short
....

编辑

当您在输入文件中检测到 \n 时,Dyp 正确指出您的附加逻辑不正确。

【讨论】:

  • 但 OP 使用 myline 添加缓冲区以形成行。 myline += buff;
  • 是的,DyP 是正确的。我在那里跳得有点快。我将编辑帖子以表明这一点。
  • 谢谢大家!我花了很多时间想知道为什么我的输出不符合预期,而不仔细考虑我的 if 语句。
猜你喜欢
  • 2016-08-29
  • 1970-01-01
  • 2017-06-14
  • 1970-01-01
  • 2012-05-15
  • 2016-08-25
  • 2020-09-02
  • 2017-06-05
  • 1970-01-01
相关资源
最近更新 更多