2
char data_[4096];
...
socket_.async_read_some(boost::asio::buffer(data_, 4096),
    boost::bind(&client::handle_read_header, this,
    boost::asio::placeholders::error,
    boost::asio::placeholders::bytes_transferred));

関数handle_read_headerが起動されると、テキストdata_に多くの\0記号が含まれます。\0どの方法を使用すると、完全な (ストリップまたはエスケープされた) 文字列を表示するのが簡単になりstd::coutますか? (デフォルトでは \0 は文字列の最後になり、他は表示されません)

4

4 に答える 4

6

Seth は、「見やすくする」というあなたの要件を親切に指摘しました。そのために:

for (size_t i = 0; i < num_bytes; ++i)
    if (buffer[i] == '\\')
        std::cout << "\\\\";
    else if (isprint(buffer[i]))
        std::cout << buffer[i];
    else
        std::cout << '\\' << std::fill(0) << std::setw(3) << buffer[i];

上記では、3 桁のバックスラッシュでエスケープされた 8 進数表記を使用して、印刷できない文字を表しています。表現を簡単に変更できます。

(単純なバイナリ書き込みの場合、文字配列/ポインターのASCIIZ規則に依存するのではstd::cout.write(buffer, num_bytes)なく、バイナリブロック書き込みを行うために呼び出すことができます。次に、結果をにパイプするか、バイナリデータを表示するのに役立つOSが提供するものにパイプできます。 NUL。)std::cout << bufferlesscat -vt

于 2012-05-01T16:06:28.763 に答える
4
std::transform( data_, data_+size, std::ostream_iterator<char>(std::cout)
              , [](char c) { c == 0 ? '*':c; });

もちろん、「*」以外のものを選択できます。現在の C++ 機能を使用できない場合は、上記のラムダが行うことを行う関数を作成してください。

于 2012-05-01T16:07:19.513 に答える
1

文字を削除するための 3 つのオプション (ご質問のとおり) は、そのままにしておく必要があるかどうかdata_、または単に文字をすばやく簡単にストリーミングする方法が必要な場合に応じて異なります。また、最後のオプションは、ヌル文字を別の (単一の) 文字に置き換える簡単な方法を示しています。C++11 をサポートしている場合は、これらすべてをラムダとして実装して、コードをより簡潔にすることができます。

#include <string>
#include <iostream>
#include <algorithm>
#include <iterator>
using namespace std;


int main()
{
   char c[] = "Ch\0ad\0's Answ\0\0\0er.";
   std::string data(c, c+19);

   std::string c1;

   struct is_null
   {
      bool operator()(const char c) const
      {
         return c == '\0';
      }
   };

   // if you need to keep data_ intact (copy)
   std::remove_copy_if(
      data.begin(),
      data.end(),
      std::back_inserter(c1),
      is_null());

   std::cout << c1 << "\n";

   // if you don't need to keep data intact, remove inline
   std::string::iterator nend = std::remove_if(
      data.begin(),
      data.end(),
      is_null());

   data.erase(nend, data.end());

   std::cout << data << "\n";

   // simplest approach, just stream out each byte and skip the null characters
   for(int x = 0; x < 19; ++x)
   {
      if(c[x] != '\0')
         cout << c[x];
   }

   cout << "\n";

   // If you want to decorate the null characters instead
   std::string data2(c, c+19);

   std::replace_if(
      data2.begin(),
      data2.end(),
      is_null(),
      '#'); // <--- this is the character that will replace the nulls

   cout << data2 << "\n";
}
于 2012-05-01T16:15:35.967 に答える
0

書き込む文字列の長さを使用して指定することにより、データを「生」(\0 を置換せずに) 端末に出力できますcout.write(読み取りハンドラーで認識される必要があります)。

それ以外の場合は、次のように、データのエスケープされたコピーを別のバッファーに作成できます。

char data_[4096];
char escaped[sizeof(data_)*2];
size_t dataLength=...;
char *readPtr=data_, *writePtr=escaped;
for( ; readPtr<data_+dataLength; readPtr++, writePtr++)
{
    switch(*readPtr)
    {
        case 0:
            *writePtr='\\';
            *++writePtr='0';
            break;
        case '\\':
            *writePtr='\\';
            *++writePtr='\\';
            break;
        default:
            *writePtr=*readPtr;
    }
}

または、書き込み中に「その場で」置き換えます(ただし、おそらく遅くなります)。

于 2012-05-01T16:06:38.810 に答える