【问题标题】:I am very confused on how to parse multiple delimiters using getline and strtok in c++我对如何在 C++ 中使用 getline 和 strtok 解析多个分隔符感到非常困惑
【发布时间】:2014-12-02 12:34:21
【问题描述】:

我的代码发布在下面。我希望能够使用分隔符“()”进行解析,并将字符串转换为 cpp 中的整数。

while(getline(fin, line))
{
    x  = atoi((strtok(line.c_str(),'(,)'));
    xx = atoi((strtok(NULL,"(),"));
    xxx = atoi((strtok(NULL,"(),")));
    cout << x << "    " << xx << "    " << xxx << "\n";
}

但由于某种原因,我收到以下错误

GraphTest.cpp:134:错误:从‘const char*’到‘char*’的无效转换

GraphTest.cpp:134:错误:正在初始化“char* strtok(c​​har*, const char*)”的参数 1

.c_str 应该将我的字符串转换为 c 类型的字符串,从而允许我使用 atoi 和 strtok 函数。我很困惑,不胜感激。

【问题讨论】:

  • 看起来你的语法很重要。为词法分析和解析选择合适的工具(例如:flex+bison 或 boost spirit,...)。
  • '(,)' 是错误的。应该是"(,)"
  • c_str() 返回一个const char*,它应该是一个指向字符串内部缓冲区的不可修改的常量指针。 strotok() 修改输入字符串以执行标记化(这就是它接受char*而不是const char*的原因)那么根本不应该那样做。
  • 这是一个 X Y 问题的例子;你使用了错误的工具来完成这项工作。退后一步,告诉我们您的输入数据是什么样的,以及所需的输出是什么。

标签: c++ delimiter text-parsing string-parsing


【解决方案1】:

我遇到了类似的问题,需要使用多个分隔符进行解析,并且在任何地方都找不到好的解决方案,所以我最终只创建了一个函数。

string getlineMultDelimiter(istream &is, string dlm, bool includeDelimiter)
{
    string str;
    char c;
    bool found = false;

    while (!found && is)
    {
        for (size_t i = 0; i < dlm.length() && !found; ++i)
            found = dlm[i] == is.peek();

        if (!found || includeDelimiter)
        {
            is.get(c);
            str += c;
        }
    }
    return str;
}

它将使用dlm字符串中的所有字符作为分隔符,您可以选择是否在返回的字符串中包含分隔符。

【讨论】:

    【解决方案2】:

    它无法编译,因为c_str() 返回一个const char*,它应该是一个指向不可修改的内部string 缓冲区的常量指针。另一方面,strtok() 接受 char*,因为它修改了其输入字符串。

    现在您有两个选择:从 strtok() 获取可用的 C 字符串或将所有内容重写为 C++。

    从您的 C++ 字符串创建一个新的可修改 C 字符串:

    char* modifiableLine = strdup(line.c_str());
    
    x  = atoi((strtok(modifiableLine, "(,)"));
    // Other processing
    
    free(modifiableLine);
    

    如果您必须在 C++ 函数/类中保留 大量 数量的 C 代码,则可以这样做。更好的解决方案是使用 C++ 标准库提供的内容(如果 C++ 11,也删除 atoi() C 函数)。我们先写一个辅助函数:

    int readNextInt(istringstream& is, const string& delimiters) {
        string token;
    
        if (getline(is, token, delimiters))
            return stoi(token);
    
        return 0; // End of stream?
    }
    

    这样使用:

    istringstream is(line)
    x = readNextInt(is, "(),");
    xx = readNextInt(is, "(),");
    xxx = readNextInt(is, "(),");
    

    请注意,标准 C++ 函数 getline() 不接受 string 作为分隔符参数,而是接受单个 char 只有这样您才需要编写自己的重载版本。查看this post 以获得良好的可能实现(您也可以在is.imbue() 之后简单地将getline() 替换为is &gt;&gt; token,参见给出的示例)。

    嗯...如果您已经在使用 Boost,那么您可以简单地使用 boost::tokenizer

    【讨论】:

      猜你喜欢
      • 2011-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-08
      • 1970-01-01
      • 1970-01-01
      • 2017-03-20
      • 2020-07-11
      相关资源
      最近更新 更多