Нет способа определить «новые» специальные символы.
Но вы можете заставить поток интерпретировать определенные символы, чтобы иметь новые значения (которые вы можете определить).Вы можете сделать это, используя 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";
}