Printing non-printable characters

Discussion in 'C++' started by Alex Vinokur, May 18, 2011.

  1. Alex Vinokur

    Alex Vinokur Guest

    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;

    if (isprint(static_cast<int>(ch)) != 0)
    {
    std::cout << ch;
    }
    else
    {
    std::cout << "\\" << std::eek:ct << 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
    Alex Vinokur, May 18, 2011
    #1
    1. Advertising

  2. On May 18, 10: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;
    >
    >         if (isprint(static_cast<int>(ch)) != 0)
    >         {
    >                         std::cout << ch;
    >                 }
    >                 else
    >         {
    >                 std::cout << "\\" << std::eek:ct << 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::eek:stream& os;
    Send2Output() : os(std::cout) {}
    void operator()(const char ch)
    {
    if (isprint(static_cast<int>(ch)) != 0)
    os << ch;
    else
    os << "\\" << std::eek:ct << 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
    Saeed Amrollahi, May 18, 2011
    #2
    1. Advertising

  3. 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;
    >
    > if (isprint(static_cast<int>(ch)) != 0)
    > {
    > std::cout<< ch;
    > }
    > else
    > {
    > std::cout<< "\\"<< std::eek:ct<< 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
    Victor Bazarov, May 18, 2011
    #3
  4. On 18 mai, 09:55, 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;
    >
    >         if (isprint(static_cast<int>(ch)) != 0)
    >         {
    >                         std::cout << ch;
    >                 }
    >                 else
    >         {
    >                 std::cout << "\\" << std::eek:ct << 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::eek:stream& 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
    Michael Doubez, May 18, 2011
    #4
  5. Alex Vinokur

    Stefan Ram Guest

    Saeed Amrollahi <> 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!)
    Stefan Ram, May 18, 2011
    #5
  6. On May 18, 5:27 pm, -berlin.de (Stefan Ram) wrote:
    > Saeed Amrollahi <> 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
    Saeed Amrollahi, May 18, 2011
    #6
  7. On 18 mai, 15:59, Michael Doubez <> wrote:
    > On 18 mai, 09:55, 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;

    >
    > >         if (isprint(static_cast<int>(ch)) != 0)
    > >         {
    > >                         std::cout << ch;
    > >                 }
    > >                 else
    > >         {
    > >                 std::cout << "\\" << std::eek:ct << 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::eek:stream operator<<(std::eek:stream & os, StringEncoder
    const & s);
    };
    std::eek:stream operator<<(std::eek:stream & os, StringEncoder const & s)
    {
    for( ....
    // your code here
    return os;
    };

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

    --
    Michael
    Michael Doubez, May 18, 2011
    #7
  8. Alex Vinokur

    Jorgen Grahn Guest

    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 .
    Jorgen Grahn, May 18, 2011
    #8
  9. * 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 != 0; ++i )


    > {
    > char ch = data;


    char const ch = data;


    >
    > 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::eek:ct<< static_cast<int>(ch)<< std::dec;
    > }


    {
    std::cout << ch;
    }
    else
    {
    std::cout << "\\" << std::eek:ct << 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>
    Alf P. Steinbach /Usenet, May 18, 2011
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Daniel Alexandre
    Replies:
    2
    Views:
    551
    Sibylle Koczian
    Mar 21, 2005
  2. metaperl
    Replies:
    1
    Views:
    292
    Peter Otten
    Feb 9, 2007
  3. Michael W. Ryder
    Replies:
    7
    Views:
    126
    Michael W. Ryder
    Apr 21, 2007
  4. Paul Harman

    Line wrapping non-printable characters

    Paul Harman, Apr 25, 2006, in forum: Perl Misc
    Replies:
    4
    Views:
    90
    Paul Harman
    Apr 26, 2006
  5. Larry
    Replies:
    19
    Views:
    285
    comp.llang.perl.moderated
    Dec 25, 2007
Loading...

Share This Page