【问题标题】:strtok or std::istringstreamstrtok 或 std::istringstream
【发布时间】:2012-11-17 01:09:03
【问题描述】:

我有以下代码,它使用 strtok 从 txt 文件接收输入。 txt文件中的输入是:

age, (4, years, 5, months)
age, (8, years, 7, months)
age, (4, years, 5, months)

我的代码如下:

char * point;
ifstream file;
file.open(file.c_str());

if(file.is_open())
{
    while(file.good())
    {
        getline(file, take);
        point = strtok(&take[0], ", ()");
    }
}

除了第 2 代和第 3 代的输出丢失外,一切正常。谁能告诉我他们为什么失踪?

我也试过istringstream,但每当我输入我的文件名时,程序就会崩溃。

char * point;
char take[256];
ifstream file;
file.open(file.c_str());

if(file.is_open())
{
    while(file.good())
    {
        cin.getline(take, 256);
        point =strtok(take,", ()");
    }
}

【问题讨论】:

  • 第二个sn-p代码是做什么的?
  • 我正在尝试使用 istringstream 做同样的事情。但是不知道为什么在输入文件名的时候会崩溃。

标签: c++ strtok istringstream


【解决方案1】:

就我个人而言,我会使用std::istringstream,但我会以不同的方式使用它(...而且,是的,我知道我也可以使用sscanf(),而且代码会更短,但我不喜欢这种类型-不安全的界面)!我会和机械手玩花样:

#include <iostream>
#include <sstream>
#include <string>

template <char C>
std::istream& skip(std::istream& in)
{
    if ((in >> std::ws).peek() != std::char_traits<char>::to_int_type(C)) {
        in.setstate(std::ios_base::failbit);
    }
    return in.ignore();
}

std::istream& (*const comma)(std::istream&) = &skip<','>;
std::istream& (*const open)(std::istream&) = &skip<'('>;
std::istream& (*const close)(std::istream&) = &skip<')'>;

struct token
{
    token(std::string const& value): value_(value) {}
    std::string::const_iterator begin() const { return this->value_.begin(); }
    std::string::const_iterator end() const   { return this->value_.end(); }
    std::string value_;
};

std::istream& operator>> (std::istream& in, token const& t)
{
    std::istreambuf_iterator<char> it(in >> std::ws), end;
    for (std::string::const_iterator sit(t.begin()), send(t.end());
         it != end && sit != send; ++it, ++sit) {
        if (*it != *sit) {
            in.setstate(std::ios_base::failbit);
            break;
        }
    }
    return in;
}

int main()
{
    std::istringstream input("age, (4, years, 5, months)\n"
                             "age , ( 8 , years , 7, months )\n"
                             "age, (4, year, 5, months)\n"
                             "age, (4, years 5, months)\n"
                             "age (4, years, 5, months)\n"
                             "age, 4, years, 5, months)\n"
                             "age, (4, years, 5, months)\n");
    std::string dummy;
    int         year, month;
    for (std::string line; std::getline(input, line); ) {
        std::istringstream lin(line);
        if (lin >> token("age") >> comma
            >> open
            >> year >> comma >> token("years") >> comma
            >> month >> comma >> token("months") >> close) {
            std::cout << "year=" << year << " month=" << month << "\n";
        }
    }
}

【讨论】:

  • 这个看起来有点大,但是很完整。
  • @Xymotech:大部分是基础设施,也可以在其他环境中使用。也许是时候研究类似于scanf() 的类型安全版本了,基于std::istream 并使用可变参数...
  • +1 用于操纵器技巧。 main 代码看起来更具可读性。
  • 对不起,有什么更简单的方法吗?因为刚开始学c++2个月,所以对你代码的大部分实现看不懂。
  • @user1823986:您可以跳过第一个操纵器并完全使用tokens。如果您不接受额外的空格,例如 age, 之间的空格,则可以将它们组合起来。 token 处理使用相当基本的 C++ 技术,例如,避免定义模板。如果您有具体问题,我可以回答。
猜你喜欢
  • 2016-02-04
  • 1970-01-01
  • 2013-05-28
  • 2010-12-20
  • 2021-02-28
  • 2015-11-17
  • 1970-01-01
  • 1970-01-01
  • 2010-09-22
相关资源
最近更新 更多