Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #5113 > unrolled thread

Printing non-printable characters

Started byAlex Vinokur <alex.vinokur@gmail.com>
First post2011-05-18 00:55 -0700
Last post2011-05-18 23:32 +0100
Articles 9 — 7 participants

Back to article view | Back to comp.lang.c++


Contents

  Printing non-printable characters Alex Vinokur <alex.vinokur@gmail.com> - 2011-05-18 00:55 -0700
    Re: Printing non-printable characters Saeed Amrollahi <amrollahi.saeed@gmail.com> - 2011-05-18 03:20 -0700
      Re: Printing non-printable characters Saeed Amrollahi <amrollahi.saeed@gmail.com> - 2011-05-18 08:00 -0700
    Re: Printing non-printable characters Victor Bazarov <v.bazarov@comcast.invalid> - 2011-05-18 09:05 -0400
    Re: Printing non-printable characters Michael Doubez <michael.doubez@free.fr> - 2011-05-18 06:59 -0700
      Re: Printing non-printable characters Michael Doubez <michael.doubez@free.fr> - 2011-05-18 08:02 -0700
      Re: Printing non-printable characters Jorgen Grahn <grahn+nntp@snipabacken.se> - 2011-05-18 21:06 +0000
    Re: Printing non-printable characters "Alf P. Steinbach /Usenet" <alf.p.steinbach+usenet@gmail.com> - 2011-05-18 23:36 +0200
      Re: Printing non-printable characters Leigh Johnston <leigh@i42.co.uk> - 2011-05-18 23:32 +0100

#5113 — Printing non-printable characters

FromAlex Vinokur <alex.vinokur@gmail.com>
Date2011-05-18 00:55 -0700
SubjectPrinting non-printable characters
Message-ID<49349a99-b157-4b5e-ac1f-570c8f06fc98@s14g2000vbi.googlegroups.com>
Hi,

// --------------------
#include <iostream>
#include <iomanip>

int main()
{
	char data[5];
  data[0] = 'a';
  data[1] = 5;
  data[2] = 'b';
  data[3] = 10;
  data[4] = 0;

  for (std::size_t i = 0; i < sizeof(data); i++)
  {
  	char ch = data[i];

  	if (isprint(static_cast<int>(ch)) != 0)
  	{
  			std::cout << ch;
  		}
  		else
  	{
  		std::cout << "\\" << std::oct << static_cast<int>(ch) << std::dec;
    }
  }
  std::cout << std::endl;

  return 0;
}

// ------------------

Output:
a\5b\12\0

Is it possible to get the same or similar output without loop in the
program?

Thanks,

Alex

[toc] | [next] | [standalone]


#5121

FromSaeed Amrollahi <amrollahi.saeed@gmail.com>
Date2011-05-18 03:20 -0700
Message-ID<2362521c-1a5a-4df8-99c9-9341fa22079f@p13g2000yqh.googlegroups.com>
In reply to#5113
On May 18, 10:55 am, Alex Vinokur <alex.vino...@gmail.com> wrote:
> Hi,
>
> // --------------------
> #include <iostream>
> #include <iomanip>
>
> int main()
> {
>         char data[5];
>   data[0] = 'a';
>   data[1] = 5;
>   data[2] = 'b';
>   data[3] = 10;
>   data[4] = 0;
>
>   for (std::size_t i = 0; i < sizeof(data); i++)
>   {
>         char ch = data[i];
>
>         if (isprint(static_cast<int>(ch)) != 0)
>         {
>                         std::cout << ch;
>                 }
>                 else
>         {
>                 std::cout << "\\" << std::oct << static_cast<int>(ch) << std::dec;
>     }
>   }
>   std::cout << std::endl;
>
>   return 0;
>
> }
>
> // ------------------
>
> Output:
> a\5b\12\0
>
> Is it possible to get the same or similar output without loop in the
> program?
>
> Thanks,
>
> Alex

Hi Alex
One typical solution is, to define a
function object and wrap the if-else statement in
overloaded function call operator, then use for_each
algorithm instead of for loop. Something like this:

#include <algorithm>
#include <iostream>
#include <iomanip>

struct Send2Output {
  std::ostream& os;
  Send2Output() : os(std::cout) {}
  void operator()(const char ch)
  {
    if (isprint(static_cast<int>(ch)) != 0)
      os << ch;
    else
      os << "\\" << std::oct << static_cast<int>(ch) << std::dec;
  }
};

int main()
{
  using namespace std;
  char data[5] = { 'a', 5, 'b', 10, 0 };
  Send2Output S2O;
  for_each(data, data + 5, S2O);
  return 0;
}

HTH
  -- Saeed Amrollahi

[toc] | [prev] | [next] | [standalone]


#5129

FromSaeed Amrollahi <amrollahi.saeed@gmail.com>
Date2011-05-18 08:00 -0700
Message-ID<57656ff4-9bd4-40f8-838f-4a461d260a1c@j13g2000pro.googlegroups.com>
In reply to#5121
On May 18, 5:27 pm, r...@zedat.fu-berlin.de (Stefan Ram) wrote:
> Saeed Amrollahi <amrollahi.sa...@gmail.com> writes:
> >>Is it possible to get the same or similar output without loop in the
> >>program?
> >for_each(data, data + 5, S2O);
>
>   That's a loop, too! It's a »for_each loop«.
>
>   A loopless solution would be something like:
>
> ::std::cout << "a5b120"
>
>   or so (I did not run the program of the OP, but one can
>   get the idea).
>
>   (Of course, one cannot print non-printable characters!)

Hi

Yes. you are right, for_each is a generic algorithm
that most likely is implemented using for or while loop.
It is a loop per se. But I guess the OP, likes to replace
an explicit loop by some implicit one, and my code did it.
In addition, his code has simple logic and mine isn't so
complex. I used combination of a generic algorithm and
a function object.

Regards,
  -- Saeed Amrollahi

[toc] | [prev] | [next] | [standalone]


#5125

FromVictor Bazarov <v.bazarov@comcast.invalid>
Date2011-05-18 09:05 -0400
Message-ID<ir0g6t$hmi$1@dont-email.me>
In reply to#5113
On 5/18/2011 3:55 AM, Alex Vinokur wrote:
> Hi,
>
> // --------------------
> #include<iostream>
> #include<iomanip>
>
> int main()
> {
> 	char data[5];
>    data[0] = 'a';
>    data[1] = 5;
>    data[2] = 'b';
>    data[3] = 10;
>    data[4] = 0;
>
>    for (std::size_t i = 0; i<  sizeof(data); i++)
>    {
>    	char ch = data[i];
>
>    	if (isprint(static_cast<int>(ch)) != 0)
>    	{
>    			std::cout<<  ch;
>    		}
>    		else
>    	{
>    		std::cout<<  "\\"<<  std::oct<<  static_cast<int>(ch)<<  std::dec;
>      }
>    }
>    std::cout<<  std::endl;
>
>    return 0;
> }
>
> // ------------------
>
> Output:
> a\5b\12\0
>
> Is it possible to get the same or similar output without loop in the
> program?

I have very little experience in that field, but for some reason it 
seems to me that a custom locale could help.  On the second thought, you 
could define your own "translating" stream buffer around the default one 
that would stuff the default with a different set of bytes if the byte 
to be output fits a particular pattern (falls in a particular range, 
etc.)  The latter method is probably easier since you could implement a 
translating buffer with the translation functor supplied at its 
instantiation, static (if you implement the buffer as a template) or 
dynamic (if you implement it as a class with a translating function as 
its c-tor argument, for instance).

V
-- 
I do not respond to top-posted replies, please don't ask

[toc] | [prev] | [next] | [standalone]


#5127

FromMichael Doubez <michael.doubez@free.fr>
Date2011-05-18 06:59 -0700
Message-ID<4395e145-bd35-41b8-a804-979018262a23@l30g2000vbn.googlegroups.com>
In reply to#5113
On 18 mai, 09:55, Alex Vinokur <alex.vino...@gmail.com> wrote:
> Hi,
>
> // --------------------
> #include <iostream>
> #include <iomanip>
>
> int main()
> {
>         char data[5];
>   data[0] = 'a';
>   data[1] = 5;
>   data[2] = 'b';
>   data[3] = 10;
>   data[4] = 0;
>
>   for (std::size_t i = 0; i < sizeof(data); i++)
>   {
>         char ch = data[i];
>
>         if (isprint(static_cast<int>(ch)) != 0)
>         {
>                         std::cout << ch;
>                 }
>                 else
>         {
>                 std::cout << "\\" << std::oct << static_cast<int>(ch) << std::dec;
>     }
>   }
>   std::cout << std::endl;
>
>   return 0;
>
> }
>
> // ------------------
>
> Output:
> a\5b\12\0
>
> Is it possible to get the same or similar output without loop in the
> program?

There is James Kanze's filtering streambuf technique. I don't have it
right now because the last time I checked, his site on neuf.fr was
down.

But you can still use a hand made streambuf filter which wrap a
streambuf and use overflow function for encoding the output (defining
the relevant underflow is left as an exercise and is much harder):

class EncodedStreambuf : public streambuf
{
  public:
    EncodedStreambuf( streambuf* sbuf );

  public: // decorates m_sbuf
    virtual int         underflow() ;
    virtual int         sync() ;
    virtual streambuf*  setbuf( char* p , int len ) ;

   // encode output
   virtual int         overflow( int ch ){
     if ( ch == EOF || isprint( ch ) ) return m_sbuf->overflow( ch );
     // should encode - chech for usual \r\n... that shouldn't be
encoded
     char code[5]="\\000";
     ch|=0x00ff;
     char* it=&code[4];
     while(ch){
       *it=ch&0x07;
       ch>>3;
     }
     return m_sbuf->xsputn(code,sizeof(code)-1);
   }

  private:
     streambuf* m_sbuf ;
} ;

Well, I hope you get the idea.
Then you can define EncodedStream that take in input a stream and
installs the wrapping streambuf in it upon construction and restore it
upon destruction.

Something like:
class EncodingOStream
{
  public:
    EncodingOStream( std::ostream& os)
      : m_encoder(os.rdbuf()) // build EncodedStreambuf
    {
      os.rdbuf(&m_encoder); // install EncodedStreambuf
    }
    ~EncodingOStream(){
       os.rdbuf(m_encoder.streambuf()); // uninstall EncodedStreambuf

     }
  // ....
};

In the final code, you simply write:

char data[5];
  data[0] = 'a';
  data[1] = 5;
  data[2] = 'b';
  data[3] = 10;
  data[4] = 0;

EncodedOstream os(std::cout);
std::cout<<data<<std::endl;

Now that I have given the hard solution, a simple solution if you
don't mind the overhead is:
std::string encodeString( std::string const & str )
{
  // boilerplate for encoding string
}
and
std::cout<<encodeString(data)<<std::endl;

--
Michael

[toc] | [prev] | [next] | [standalone]


#5130

FromMichael Doubez <michael.doubez@free.fr>
Date2011-05-18 08:02 -0700
Message-ID<c51c7b24-a18a-4d0e-b26a-0861c14a14f8@e8g2000vbz.googlegroups.com>
In reply to#5127
On 18 mai, 15:59, Michael Doubez <michael.dou...@free.fr> wrote:
> On 18 mai, 09:55, Alex Vinokur <alex.vino...@gmail.com> wrote:
>
>
>
>
>
>
>
>
>
> > Hi,
>
> > // --------------------
> > #include <iostream>
> > #include <iomanip>
>
> > int main()
> > {
> >         char data[5];
> >   data[0] = 'a';
> >   data[1] = 5;
> >   data[2] = 'b';
> >   data[3] = 10;
> >   data[4] = 0;
>
> >   for (std::size_t i = 0; i < sizeof(data); i++)
> >   {
> >         char ch = data[i];
>
> >         if (isprint(static_cast<int>(ch)) != 0)
> >         {
> >                         std::cout << ch;
> >                 }
> >                 else
> >         {
> >                 std::cout << "\\" << std::oct << static_cast<int>(ch) << std::dec;
> >     }
> >   }
> >   std::cout << std::endl;
>
> >   return 0;
>
> > }
>
> > // ------------------
>
> > Output:
> > a\5b\12\0
>
> > Is it possible to get the same or similar output without loop in the
> > program?

[snip]

Another solution is the class wrapper:

class EscapedString
{
public:
   explicit EscapedString(char const * str )m_str(str){}
protected:
   char const * m_str;
   friend std::ostream operator<<(std::ostream & os, StringEncoder
const & s);
};
std::ostream operator<<(std::ostream & os, StringEncoder const & s)
{
 for( ....
 // your code here
 return os;
};

And you use:
std::cout<<EscapedString(data)<<std::cout;

--
Michael

[toc] | [prev] | [next] | [standalone]


#5143

FromJorgen Grahn <grahn+nntp@snipabacken.se>
Date2011-05-18 21:06 +0000
Message-ID<slrnit8d6k.gtj.grahn+nntp@frailea.sa.invalid>
In reply to#5127
On Wed, 2011-05-18, Michael Doubez wrote:
...
> There is James Kanze's filtering streambuf technique. I don't have it
> right now because the last time I checked, his site on neuf.fr was
> down.

I /think/ he wrote that particular site is permanently down.

James, please make that information available somewhere! 
It's obviously of interest to some of us, or we wouldn't have
remembered it.

/Jorgen

-- 
  // Jorgen Grahn <grahn@  Oo  o.   .  .
\X/     snipabacken.se>   O  o   .

[toc] | [prev] | [next] | [standalone]


#5146

From"Alf P. Steinbach /Usenet" <alf.p.steinbach+usenet@gmail.com>
Date2011-05-18 23:36 +0200
Message-ID<ir1dqa$5uj$1@dont-email.me>
In reply to#5113
* Alex Vinokur, on 18.05.2011 09:55:
> Hi,
>
> // --------------------
> #include<iostream>
> #include<iomanip>

Add relevant header for 'isprint'.


> int main()
> {
> 	char data[5];
>    data[0] = 'a';
>    data[1] = 5;
>    data[2] = 'b';
>    data[3] = 10;
>    data[4] = 0;

     char const data[] = "a\005b\012";

Or thereabouts. It's a long time since I used that silly octal notation. :-)


>    for (std::size_t i = 0; i<  sizeof(data); i++)

     for( int i = 0;  data[i] != 0;  ++i )


>    {
>    	char ch = data[i];

     char const ch = data[i];


>
>    	if (isprint(static_cast<int>(ch)) != 0)

     if( isprint( static_cast<unsigned char>( ch ) ) != 0 )

While the earlier things are mostly style, the type of this cast is important to 
avoid Undefined Behavior. If you can guaranteee ASCII only data then it does not 
matter, but then you don't need any cast. The correct type is 'unsigned char' 
(with a subsequent implicit conversion to 'int').


>    	{
>    			std::cout<<  ch;
>    		}
>    		else
>    	{
>    		std::cout<<  "\\"<<  std::oct<<  static_cast<int>(ch)<<  std::dec;
>      }

     {
         std::cout << ch;
     }
     else
     {
         std::cout << "\\" << std::oct << ch+0 << std::dec;
     }

Please convert tab characters to spaces before posting.

>    }
>    std::cout<<  std::endl;
>
>    return 0;
> }
>
> // ------------------
>
> Output:
> a\5b\12\0
>
> Is it possible to get the same or similar output without loop in the
> program?

There will be a loop somewhere.

The only question is how indirect and hidden you want it.

In general it's better with explicit code than indirect, hidden, implicit code.


Cheers & hth.,

- Alf

-- 
blog at <url: http://alfps.wordpress.com>

[toc] | [prev] | [next] | [standalone]


#5150

FromLeigh Johnston <leigh@i42.co.uk>
Date2011-05-18 23:32 +0100
Message-ID<iamdnXB6OYl-1UnQnZ2dnUVZ8qCdnZ2d@giganews.com>
In reply to#5146
On 18/05/2011 22:36, Alf P. Steinbach /Usenet wrote:
> * Alex Vinokur, on 18.05.2011 09:55:
>
>
>> for (std::size_t i = 0; i< sizeof(data); i++)
>
> for( int i = 0; data[i] != 0; ++i )
>

Ignore Alf on this point (he has a bee in his bonnet about it); 
std::size_t is perfectly fine if not even more desirable than int as 
array indices cannot be negative.

I still would have written something slightly different:

for (std::size_t i = 0; i != sizeof(data); ++i)

but this definitely is mostly a matter of style.

/Leigh

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c++


csiph-web