简体   繁体   中英

how to define my own special character in cout

for example :

cout << "  hello\n400";

will print:

  hello
400

another example:

cout << "  hello\r400";

will print:

400ello

there is a option to define my own special character? i would like to make somthing like:

cout << "  hello\d400";

would give:

  hello
  400

(/d is my special character, and i already got the function to get the stdout cursor one line down(cursorDown()),but i just don't how to define a special character that each time will be writted will call to my cursorDown() function)

As said by others there is no way you can make cout understand user defined characters , however what you could do is

  • std::cout is an object of type std::ostream which overloads operator<<. You could create an object of the struct which parses your string for your special characters and other user defined characters before printing it to a file or console using ostream similar to any log stream. Example

or

  • Instead of calling cout << "something\\dsomething" you can call a method special_cout(std::string); which parses the string for user defined characters and executes the calls.

There is no way to define "new" special characters.

But you can make the stream interpret specific characters to have new meanings (that you can define). You can do this using locals.

Some things to note:

The characters in the string "xyza" is just a simple way of encoding a string. Escaped characters are C++ way of allowing you to represent representing characters that are not visible but are well defined. Have a look at an ASCII table and you will see that all characters in the range 00 -> 31 (decimal) have special meanings (often referred to as control characters).

See Here: http://www.asciitable.com/

You can place any character into a string by using the escape sequence to specify its exact value; ie \\x0A used in a string puts the "New Line" character in the string.

The more commonly used "control characters" have shorthand versions (defined by the C++ language). '\\n' => '\\x0A' but you can not add new special shorthand characters as this is just a convenience supply by the language (its like a tradition that most languages support).

But given a character can you give it a special meaning in an IO stream. YES . You need to define a facet for a locale then apply that locale to the stream.

Note: Now there is a problem with applying locals to std::cin / std::out . If the stream has already been used (in any way) applying a local may fail and the OS may do stuff with the stream before you reach main() and thus applying a locale to std::cin / std::cout may fail (but you can do it to file and string streams easily).

So how do we do it.

Lets use "Vertical Tab" as the character we want to change the meaning of. I pick this as there is a shortcut for it \\v (so its shorter to type than \\x0B ) and usually has no meaning for terminals.

Lets define the meaning as new line and indent 3 spaces.

#include <locale>
#include <algorithm>
#include <iostream>
#include <fstream>

class IndentFacet: public std::codecvt<char,char,std::mbstate_t>
{
  public:
   explicit IndentFacet(size_t ref = 0): std::codecvt<char,char,std::mbstate_t>(ref)    {}  

    typedef std::codecvt_base::result               result;
    typedef std::codecvt<char,char,std::mbstate_t>  parent;
    typedef parent::intern_type                     intern_type;
    typedef parent::extern_type                     extern_type;
    typedef parent::state_type                      state_type;

  protected:
    virtual result do_out(state_type& tabNeeded,
                         const intern_type* rStart, const intern_type*  rEnd, const intern_type*&   rNewStart,
                         extern_type*       wStart, extern_type*        wEnd, extern_type*&         wNewStart) const
    {   
        result  res = std::codecvt_base::ok;

        for(;(rStart < rEnd) && (wStart < wEnd);++rStart,++wStart)
        {   
            if (*rStart == '\v')
            {   
                if (wEnd - wStart < 4)
                {   
                    // We do not have enough space to convert the '\v`
                    // So stop converting and a subsequent call should do it.
                    res = std::codecvt_base::partial;
                    break;
                }   
                // if we find the special character add a new line and three spaces
                wStart[0] = '\n';
                wStart[1] = ' ';
                wStart[2] = ' ';
                wStart[3] = ' ';

                // Note we do +1 in the for() loop
                wStart += 3;
            }   
            else
            {
                // Otherwise just copy the character.
                *wStart             = *rStart;
            }   
        }   

        // Update the read and write points.
        rNewStart   = rStart;
        wNewStart   = wStart;

        // return the appropriate result.
        return res;
    }   

    // Override so the do_out() virtual function is called.
    virtual bool do_always_noconv() const throw()
    {   
        return false;   // Sometime we add extra tabs
    }   

};

Some code that uses the locale.

int main()
{
    std::ios::sync_with_stdio(false);

    /* Imbue std::cout before it is used */
    std::cout.imbue(std::locale(std::locale::classic(), new IndentFacet()));

    // Notice the use of '\v' after the first lien
    std::cout << "Line 1\vLine 2\nLine 3\n";

    /* You must imbue a file stream before it is opened. */
    std::ofstream       data;
    data.imbue(std::locale(std::locale::classic(), new IndentFacet()));
    data.open("PLOP");

    // Notice the use of '\v' after the first lien
    data << "Loki\vUses Locale\nTo do something silly\n";
}

The output:

> ./a.out
Line 1
   Line 2
Line 3
> cat PLOP
Loki
   Uses Locale
To do something silly

BUT

Now writing all this is not really worth it. If you want a fixed indent like that us a named variable that has those specific characters in it. It makes your code slightly more verbose but does the trick.

#include <string>
#include <iostream>

std::string const newLineWithIndent = "\n   ";

int main()
{
    std::cout << "  hello" << newLineWithIndent << "400";
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM