1

给定数据格式为“int,int,...,int,string,int”,是否可以(仅)使用 stringstream 来正确解码字段?

[代码]

int main(int c, char** v)
{
    std::string line = "0,1,2,3,4,5,CT_O,6";
    char delimiter[7];
    int id, ag, lid, cid, fid, did, j = -12345;
    char dcontact[4]; // <- The size of <string-field> is known and fixed
    std::stringstream ssline(line);
    ssline >> id >> delimiter[0]
    >> ag >> delimiter[1]
    >> lid >> delimiter[2]
    >> cid >> delimiter[3]
    >> fid >> delimiter[4]
    >> did >> delimiter[5]  // <- should I do something here?
    >> dcontact >> delimiter[6]
    >> j;
    std::cout << id << ":" << ag << ":" << lid << ":" << cid << ":" << fid << ":" << did << ":";
    std::cout << dcontact << "\n";
}

[输出] ,粗体部分显示 stringstream 无法仅读取 4 char 到 dcontact。实际上持有超过 4 个字符,留下垃圾数据。0:1:2:3:4:5:CT_6,0:-45689dcontactj

4

5 回答 5

1

operator >> (istream&, char[N])是的,对于 N没有特定的重载,char*因此它认为这是最佳匹配。char* 的重载读取到下一个空白字符,因此它不会在逗号处停止。

您可以将您的 dcontact 包装在一个结构中,并有一个特定的重载来读入您的结构。否则,您可以使用 read,尽管它会破坏您可爱的>>运算符链。

ssline.read( dcontact, 4 );

届时将起作用。

顺便说一句,要读取一个分隔符,您可以使用getline. (get也可以,但getline自由函数写入 astd::string将意味着您不必猜测长度)。

(请注意,其他人已指定使用get而不是read,但在您的情况下这将失败,因为您的数组末尾没有额外的字节dcontact作为空终止符。如果您想dcontact以空终止,则将其设为 5字符并使用“get”,将为您附加空值)。

于 2013-01-03T13:27:29.687 回答
1

稍微更健壮(','正确处理分隔符):

template <char D>
std::istream& delim(std::istream& in)
{
  char c;
  if (in >> c && c != D) in.setstate(std::ios_base::failbit);
  return in;
}

int main()
{
  std::string line = "0,1,2,3,4,5,CT_O,6";
  int id, ag, lid, cid, fid, did, j = -12345;
  char dcontact[5]; // <- The size of <string-field> is known and fixed
  std::stringstream ssline(line);
  (ssline >> id >> delim<','>
          >> ag >> delim<','>
          >> lid >> delim<','>
          >> cid >> delim<','>
          >> fid >> delim<','>
          >> did >> delim<','> >> std::ws
          ).get(dcontact, 5, ',') >> delim<','>
          >> j;
  std::cout << id << ":" << ag << ":" << lid << ":"
            << cid << ":" << fid << ":" << did << ":";
            << dcontact << "\n";
}
于 2013-01-03T13:35:25.927 回答
0

试试这个

  int main(int c, char** v) {
    string line = "0,1,2,3,4,5,CT_O,6";
    char delimiter[7];
    int id, ag, lid, cid, fid, did, j = -12345;
    char dcontact[5]; // <- The size of <string-field> is known and fixed

    stringstream ssline(line);

    ssline >> id >> delimiter[0]
            >> ag >> delimiter[1]
            >> lid >> delimiter[2]
            >> cid >> delimiter[3]
            >> fid >> delimiter[4]
            >> did >> delimiter[5];

    ssline.get(dcontact, 5);

    ssline >> delimiter[6]
            >> j;
    std::cout << id << ":" << ag << ":" << lid << ":" << cid << ":" << fid << ":" << did << ":";
    std::cout << dcontact << "\n" << j;
    }
于 2013-01-03T13:31:20.320 回答
0

问题是>>字符串(std::string或 C 风格字符串)的运算符实际上实现了单词的语义,具有特定的单词定义。这个决定是任意的(我会把它写成一行),但由于一个字符串可以代表许多不同的东西,他们必须选择一些东西。

通常,解决方案是永远不要>>在字符串上使用。定义您想要的类(在这里,可能类似于 Symbol),并>>为它定义一个尊重其语义的运算符。你的代码会更清晰,你可以根据需要添加各种不变的控件。如果您知道该字段始终恰好是四个字符,则可以执行以下简单操作:

class DContactSymbol
{
    char myName[ 4 ];
public:
    //  ...
    friend std::istream&
    operator>>( std::istream& source, DContactSymbol& dest );
    //  ...
};

std::istream&
operator>>( std::istream& source, DContactSymbol& dest )
{
    std::sentry guard( source );
    if ( source ) {
        std::string tmp;
        std::streambuf* sb = source.rdbuf();
        int ch = sb->sgetc();
        while ( source && (isalnum( ch ) || ch == '_') ) {
            tmp += static_cast< char >( ch );
            if ( tmp.size() > sizeof( dest.myName ) ) {
                source.setstate( std::ios_base::failbit );
            }
        }
        if ( ch == source::traits_type::eof() ) {
            source.setstate( std::ios_base::eofbit );
        }
        if ( tmp.size() != sizeof( dest.myName ) ) {
            source.setstate( std::ios_base::failbit );
        }
        if ( source ) {
            tmp.copy( dest.myName, sizeof( dest.myName ) );
        }
    }
    return source;
}

(请注意,与其他一些建议不同,例如 using ,此建议保持所有通常的约定,例如跳过依赖于标志std::istream::read的前导空白 。)skipws

当然,如果你不能保证 100% 的符号永远是 4 个字符,你应该使用std::string它,并相应地修改>>操作符。

顺便说一句,您似乎想将四个字符读入 dcontact,尽管它只够三个字符(因为 >>会插入一个终止符'\0')。如果您阅读的内容超过三个,则您的行为未定义。

于 2013-01-03T14:33:09.783 回答
0

由于字符串的长度是已知的,您可以使用std::setw(4),如

ssline >> std::setw(4) >> dcontact >> delimiter[6];
于 2013-01-05T00:10:42.607 回答