簡體   English   中英

C ++ stringstream以固定長度字符串讀取到char數組

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM