【问题标题】:comma separated stream into struct逗号分隔的流到结构
【发布时间】:2013-05-15 17:00:47
【问题描述】:

我有一个包含一个 int 和两个字符串的结构。读取文件时,前两个值以逗号分隔,最后一个值以换行符终止。但是,第三个参数可能为空。

前数据:7, john doe, 123-456-7891 123 fake st.

我想这样做,以便我的程序将获取第一个数字并将其放入 int,找到逗号并将第二个数字放入结构的字符串等。

第一个问题是我应该改用类吗?我见过getline(stream, myString, ',');,但我的参数是不同的数据类型,所以我不能把它们都扔到一个向量中。

我的代码:

struct Person{
    int id;//dont care if this is unique 
    string name;
    string extraInfo;
};

int main(int argc, char* argv[]){
    assert( argc ==2 && "Invalid number of command line arguments");
    ifstream inputFile (argv[1]);
    assert( inputFile.is_open() && "Unable to open file");
}

存储此信息并从前两个逗号分隔并以换行符结尾的文件中检索它的最佳方法是什么?我还希望程序忽略文件中的空白行。

【问题讨论】:

  • 数据是 CSV 格式,还是只是您自己的编码,保证字符串值周围的双引号? (在 CSV 中,在某些情况下不需要它们,例如某人只使用一个名字,例如麦当娜)。
  • 引号永远不存在,我猜是坏习惯。删除它们。

标签: c++ file-io struct io stream


【解决方案1】:

我会使用普通的getline() 逐行读取文件。然后,将其放入stringstream 中进行进一步解析或使用stringfind() 函数手动拆分文本。

还有一些注意事项:

  • 我不明白您关于使用类的第一个问题。如果你的意思是Person,那么答案是没关系。
  • 对您无法控制的事物使用断言是错误的,例如 argc。这应该只用于验证您没有犯编程错误。另外,如果你#define NDEBUG,断言全部消失,所以它们不应该成为你程序逻辑的一部分。改为抛出 std::runtime_error("failed to open file")。
  • 您可能不希望字符串中出现双引号。此外,您可能希望 "a,b" 不被逗号分隔。确保您有断言所需功能的测试。

【讨论】:

  • 1- 我认为一个类可能会有一些不同。2-我的程序应该始终有 2 个命令行参数。 3- 我不是故意加引号的,我把它们去掉了。
  • 我知道它应该有两个参数,但这不是您可以通过程序代码控制的,您只能验证它是否被正确调用。 assert() 旨在捕获编程错误,因此不适合运行时检查。您的使用没有错,只是违反约定并发送错误的隐式消息。
【解决方案2】:

您仍然可以使用getline 方法来标记一行,但您首先必须阅读该行:

vector<Person> people;
string line;
int lineNum = 0;

while( getline(inputFile, line) )
{
    istringstream iss(line);
    lineNum++;

    // Try to extract person data from the line.  If successful, ok will be true.
    Person p;
    bool ok = false;

    do {
        string val;
        if( !getline(iss, val, ',') ) break;
        p.id = strtol( val.c_str(), NULL, 10 );

        if( !getline(iss, p.name, ',') ) break;
        if( !getline(iss, p.extraInfo, ',') ) break;

        // Now you can trim the name and extraInfo strings to remove spaces and quotes
        //[todo]

        ok = true;
    } while(false);

    // If all is well, add the person to our people-vector.
    if( ok ) {
        people.push_back(p);
    } else {
        cout << "Failed to parse line " << lineNum << ": " << line << endl;
    }
}

【讨论】:

  • lineNum 的用途是什么?
  • 行号。不知道你,我只是有这种计数行的习惯,这样当我得到一个错误时,我可以输出它发生在哪一行。你会看到我在底部使用它以防出错。请注意,此代码不处理引号等。为此,您最好创建一个快速函数,将单引号或未引用的字符串从流中拉出(这样您就不会在错误的逗号处中断)。
【解决方案3】:

使用 getline 获取字符串中的行后,使用 strtok。

char myline[] = "7, john doe, 123-456-7891 123 fake st.";
char tokens = strtok(myline, ",");
while(tokens)
{
    //store tokens in your struct values here
}

您需要包含 #include &lt;string.h&gt; 才能使用 strtok

【讨论】:

    猜你喜欢
    • 2016-10-25
    • 2018-10-02
    • 2020-08-08
    • 1970-01-01
    • 2021-11-29
    • 1970-01-01
    • 2021-11-17
    相关资源
    最近更新 更多