如果数据格式为“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";
}
[输出] 0:1:2:3:4:5:CT_6,0:-45689
,粗体部分显示stringstream无法读取4个字符仅用于dcontact。 dcontact
实际上拥有4个以上的字符,为j
留下了垃圾数据。
答案 0 :(得分:1)
是的,N operator >> (istream&, char[N])
没有特定的重载,char*
也有>>
,因此它认为是最佳匹配。 char *的重载读取到下一个空格字符,因此它不会停留在逗号处。
你可以将你的dcontact包装在一个结构中,并有一个特定的重载来读入你的结构。否则你可以使用read,虽然它打破了你可爱的ssline.read( dcontact, 4 );
运营商链。
getline
将在那时工作。
要读取分隔符,顺便提一下,您可以使用get
。 (getline
也可以正常工作,std::string
写get
自由函数意味着您无需猜测长度。
(请注意,其他人已指定使用read
而不是dcontact
,但由于您dcontact
末尾没有额外的字节,因此您的情况会失败如果你希望{{1}}以空值终止,那么使它成为5个字符并使用'get`并为你追加null。
答案 1 :(得分: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";
}
答案 2 :(得分: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;
}
答案 3 :(得分:0)
问题是字符串的>>
运算符
(std::string
或C样式字符串)实际上实现了
单词的语义,具有单词的特定定义。该
决定是任意的(我会把它作为一条线),但从那以后
一个字符串可以表示许多不同的东西,他们必须选择
东西。
通常,解决方案是不要在字符串上使用>>
。
定义你想要的类(这里可能是类似的
Symbol
),并为其定义一个尊重它的运算符>>
语义。你的代码将更加清晰,而你
可以根据需要添加各种invarant控件。如果你知道的话
那个字段总是正好四个字符,你可以做到
简单的事情:
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;
}
(请注意,与其他一些建议不同,例如
使用std::istream::read
,这个保持所有常见的
约定,例如跳过依赖于的前导空格
skipws
标志。)
当然,如果你不能100%保证这个符号会
永远是4个字符,你应该使用std::string
,和
相应地修改>>
运算符。
顺便说一下,你好像想要读四个字
dcontact
,虽然它只有三个足够大(因为
>>
将插入终止'\0'
)。如果你再读一遍了
三个进入它,你有不确定的行为。
答案 4 :(得分:0)
由于字符串的长度已知,您可以使用std::setw(4)
,如
ssline >> std::setw(4) >> dcontact >> delimiter[6];