как определить свой собственный специальный символ в Cout - PullRequest
0 голосов
/ 04 марта 2019

например:

cout << "  hello\n400";

напечатает:

  hello
400

другой пример:

cout << "  hello\r400";

напечатает:

400ello

есть опция для определения моего специального символа?я хотел бы сделать что-то вроде:

cout << "  hello\d400";

даст:

  hello
  400

(/ d - мой специальный символ, и я уже получил функцию для получения курсора stdout на одну строкувниз (cursorDown ()), но я просто не знаю, как определить специальный символ, который будет записываться каждый раз при вызове моей функции cursorDown ())

Ответы [ 2 ]

0 голосов
/ 05 марта 2019

Нет способа определить «новые» специальные символы.

Но вы можете заставить поток интерпретировать определенные символы, чтобы иметь новые значения (которые вы можете определить).Вы можете сделать это, используя locals.

Обратите внимание:

Символы в строке "xyza" - это простой способ кодирования строки.Экранированные символы - это способ C ++, позволяющий вам представлять представляющие символы, которые не видны, но хорошо определены.Посмотрите на таблицу ASCII, и вы увидите, что все символы в диапазоне 00 -> 31 (десятичные) имеют специальные значения (часто называемые управляющими символами).

См. Здесь: http://www.asciitable.com/

Вы можете поместить любой символ в строку, используя escape-последовательность, чтобы указать ее точное значение;т. е. \x0A используемый в строке помещает в строку символ «Новая строка».

Более часто используемые «управляющие символы» имеют сокращенные версии (определенные в языке C ++).'\n' => '\x0A' но вы не можете добавлять новые специальные сокращенные символы, поскольку это просто удобная поставка для языка (это как традиция, которую поддерживает большинство языков).

Но, учитывая символ, вы можете придать ему особое значениев потоке ввода-вывода. ДА * * тысяча двадцать-одна.Вам необходимо определить фасет для локали, а затем применить эту локаль к потоку.

Примечание. Теперь существует проблема с применением локальных значений к 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";
}
0 голосов
/ 04 марта 2019

Как говорили другие, вы не можете заставить cout понимать определяемые пользователем символы, однако вы можете сделать это:

  • std :: cout - это объект типа std :: ostream, который перегружаетоператор <<.Вы можете создать объект структуры, который анализирует вашу строку для ваших специальных символов и других пользовательских символов, прежде чем печатать его в файл или консоль, используя ostream, похожий на любой поток журнала.<a href="https://stackoverflow.com/questions/28217643/how-to-create-functions-like-stdcout"> Пример

или

  • Вместо вызова cout << "something\dsomething" вы можете вызвать метод special_cout(std::string);, который анализирует строку для определенных пользователем символов и выполняетзвонки.
...