如何在cout中定义自己的特殊字符

问题描述 投票:1回答:2

例如 :

cout << "  hello\n400";

将打印:

  hello
400

另一个例子:

cout << "  hello\r400";

将打印:

400ello

有一个选项来定义我自己的特殊字符?我想做的事情如下:

cout << "  hello\d400";

会给:

  hello
  400

(/ d是我的特殊字符,我已经得到了将stdout光标向下一行(cursorDown())的函数,但我不知道如何定义每次写入的特殊字符都会调用我的cursorDown()函数)

c++ stdout cursor-position
2个回答
1
投票

无法定义“新”特殊字符。

但是,您可以使流解释特定字符以具有新的含义(您可以定义)。你可以使用当地人这样做。

有些事情需要注意:

字符串"xyza"中的字符只是编码字符串的简单方法。转义字符是C ++允许您表示不可见但定义明确的字符的方式。看一下ASCII表,您将看到00 -> 31(十进制)范围内的所有字符都有特殊含义(通常称为控制字符)。

见这里:http://www.asciitable.com/

您可以使用转义序列将任何字符放入字符串中以指定其确切值;即字符串中使用的\x0A将“New Line”字符放入字符串中。

更常用的“控制字符”有简写版本(由C ++语言定义)。 '\n' => '\x0A'但你不能添加新的特殊速记字符,因为这只是语言的便利供应(它像大多数语言支持的传统)。

但是给定一个字符可以在IO流中赋予它特殊的含义。是。您需要为区域设置定义构面,然后将该区域设置应用于流。

注意:现在将局部应用于std::cin / std::out时出现问题。如果已经使用了流(以任何方式),则应用本地可能会失败,并且操作系统可能会在到达main()之前对流进行处理,因此将区域设置应用于std::cin / std::cout可能会失败(但您可以将其用于文件和字符串流很容易)。

那我们该怎么做呢。

让我们使用“垂直制表符”作为我们想要改变其含义的字符。我选择它,因为它有一个快捷方式\v(所以它的类型比\x0B更短)并且通常对终端没有意义。

让我们将意义定义为新行和缩进3空格。

#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
    }   

};

一些使用区域设置的代码。

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";
}

输出:

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

现在写这一切并不值得。如果你想要一个像我们这样的固定缩进,那么一个命名变量中包含那些特定的字符。它使你的代码稍微冗长,但是做到了。

#include <string>
#include <iostream>

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

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

2
投票

正如其他人所说,你无法让cout理解用户定义的角色,但你可以做的是

  • std :: cout是std :: ostream类型的对象,它重载了operator <<。您可以创建struct的对象,该对象在使用类似于任何日志流的ostream将其打印到文件或控制台之前,为特殊字符和其他用户定义的字符解析字符串。 Example

要么

  • 您可以调用方法cout << "something\dsomething"而不是调用special_cout(std::string);,该方法解析用户定义字符的字符串并执行调用。
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.