[英]C++ stringstream read in fixed length string to char array
給定數據格式為“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
,粗體部分顯示0:1:2:3:4:5: CT_6,0 :-45689
無法讀取4個字符僅用於dcontact。 dcontact
實際上擁有超過4個字符,留下j
與垃圾數據。
是的,對於N, operator >> (istream&, char[N])
沒有特定的重載,並且存在char*
因此它將其視為最佳匹配。 char *的重載讀取到下一個空格字符,因此它不會停留在逗號處。
你可以將你的dcontact包裝在一個結構中,並有一個特定的重載來讀入你的結構。 否則你可以使用閱讀,雖然它打破了你可愛的>>
運營商鏈。
ssline.read( dcontact, 4 );
將在那一點工作。
順便說一句,要讀取分隔符,可以使用getline
。 ( get
也可以工作,但getline
自由函數寫入std::string
意味着你不必猜測長度)。
(注意,其他人已經指定使用get
而不是read
,但是在你的情況下這將失敗,因為你的dcontact
數組末尾沒有額外的字節用於null終止符。如果你想dcontact
是null終止的然后使它成為5個字符並使用'get`並為您附加null。
稍微強一些(正確處理','
分隔符):
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";
}
嘗試這個
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;
}
問題是字符串的>>
運算符( 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'
)。 如果你讀了三個以上,你有不確定的行為。
由於字符串的長度已知,因此您可以使用std::setw(4)
,如
ssline >> std::setw(4) >> dcontact >> delimiter[6];
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.