Variadic-аргументы обычно расходуются по порядку. Также поддерживается
синтаксис позиционных параметров в стиле POSIX. Каждый аргумент форматируется в последовательность символов в соответствии со спецификацией формата, и символы передаются в
w. Используется и форматируется столько аргументов, сколько указано в форматирующей строке. Если аргументов меньше, чем спецификаторов формата, то генерируется исключение
FormatException. Если аргументов больше, чем требуется спецификацией формата, они игнорируются, но только если был отформатирован хотя бы один аргумент.
Форматирующая строка поддерживает форматирование массивов и вложенных в массив элементов через группирующие спецификаторы формата
% (и
%). Каждая пара
% (и
%) соответствует одному аргументу-массиву. Вложенная форматирующая под-строка применяется к отдельным элементам массива. Конечная часть форматирующей под-строки, следующая за спецификатором преобразования для элемента массива, интерпретируется как разделитель массива и поэтому опускается после последнего элемента массива. Спецификатор
%| может использоваться для явного указания начала разделителя, так что идущая до него часть строки будет включена после последнего элемента массива. (Ниже приведены конкретные примеры).
Форматирующая строка:
Форматирующая строка
состоит из символов вперемешку со спецификациями формата. Символы просто копируются на выход (например, putc) после любого необходимого преобразования в соответствующую UTF8-последовательность.
Форматирующая строка имеет следующую грамматику (
переводы элементов грамматики, представляющих слова и словосочетания, приведены мной в виде комментария – прим.пер.):
FormatString:
FormatStringItem*
FormatStringItem:
'%%'
'%' Position Flags Width Precision FormatChar
'%(' FormatString '%)'
OtherCharacterExceptPercent
Position:
empty
Integer '$'
Flags:
empty
'-' Flags
'+' Flags
'#' Flags
'0' Flags
' ' Flags
Width:
empty
Integer
'*'
Precision:
empty
'.'
'.' Integer
'.*'
Integer:
Digit
Digit Integer
Digit:
'0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
FormatChar:
's'|'c'|'b'|'d'|'o'|'x'|'X'|'e'|'E'|'f'|'F'|'g'|'G'|'a'|'A'
Флаги влияют на форматирование в зависимости от спецификатора следующим образом.
Флаг | Связанные типы | Семантика |
'-' | числовой |
Левое выравнивание результата в поле. Перекрывает флаг 0.
|
'+' | числовой |
У положительных чисел добавляется префикс в виде символа +. Прекрывает любой пробельный флаг.
|
'#' | целый ('o') |
Добавляется точность при необходимости, чтобы первая цифра восьмеричного форматирования была "0", даже если аргумент и Precision (точность) равны нулю.
|
'#' | целый ('x', 'X') |
При ненулевом аргументе к результату добавляется префикс 0x (0X).
|
'#' | с плавающей точкой |
Всегда вставлять десятичную точку и печать хвостовые нули.
|
'0' | числовой |
Использовать ведущие нули для заполнения вместо пробелов (кроме значений с плавающей точкой, nan и infinity). Игнорируется, если присутсвует Precision (точность).
|
' ' | числовой |
Префиксом положительных чисел в знаковом преобразовании будет пробел.
|
- Width (ширина)
-
Определяет минимальную ширину поля. Если ширина равна *, то в качестве ширины принимается дополнительный аргумент типа int, предшествующий фактическому аргументу. Если ширина отрицательная, считается, что таким образом задан Флаг с символом -.
- Precision (точность)
-
Дает точность для числовых преобразований. Если точность равна *, то в качестве точности принимается дополнительный аргумент типа int, предшествующий фактическому аргументу. Если он отрицательный, это как если бы не было спецификатора Precision.
- FormatChar (форматирующий символ)
-
- 's'
- Соответствующий аргумент форматируется в зависимости от его типа:
- bool
- Результат равен "true" или "false".
- целые типы
- Используется формат %d.
- типы с плавающей точкой
- Используется формат %g.
- строковые типы
-
Результатом является строка, преобразованная в UTF-8. Precision задает максимальное число символов, используемых в результате.
- структуры
-
Если у структуры определён метод toString(), результатом является строка, возвращаемая из этой функции. В противном случае результатом будет StructName(field0, field1, ...), где fieldn является n-м элементом, отформатированным по умолчанию.
- классы, унаследованные от Object
-
Результатом является строка, возвращаемая методом .toString() экземпляра класса. Precision задаёт максимальное количество символов для использования в результате.
- объединения
-
Если объединение определяет метод toString(), результатом является строка, возвращаемая из этой функции. В противном случае результатом будет имя объединения, без его содержимого.
- не-строковые статические и динамические массивы
-
Результатом является [s0, s1, ...], где sn – это n-й элемент, отформатированный по умолчанию.
- ассоциативные массивы
-
Результат эквивалентен тому, как будет выглядеть инициализатор для содержимого ассоциативного массива, например: ["red" : 10, "blue" : 20].
- 'c'
-
Соответствующий аргумент должен быть символьным типом.
- 'b','d','o','x','X'
-
Соответствующий аргумент должен быть целым типом, и он форматируется как целое. Если аргумент является знаковым типом, а FormatChar – это d, он преобразуется в строку символов со знаком, иначе он обрабатывается как беззнаковый. Аргумент типа bool форматируется как '1' или '0'. Используется двоичная база для b, восьмеричная для o, десятичная для d и шестнадцатеричная для x или X. Форматы x используют строчные буквы, X используют буквы в верхнем регистре. Если количество результирующих цифр меньше, чем точность, то при необходимости используются ведущие нули. Если Precision равно 0, и число равно 0, цифры не выводятся в результат.
- 'e','E'
-
Число с плавающей точкой форматируется как одна цифра перед десятичной точкой, Precision (точность) цифр после, FormatChar, ±, за которыми следует как минимум двухзначное значение порядка: d.dddddde±dd. Если Precision отсутствует, после десятичной точки генерируются шесть цифр. Если Precision равно 0, десятичная точка не формируется.
- 'f','F'
-
Число с плавающей точкой форматируется в десятичной нотации. Precision (точность) указывает количество цифр, генерируемых после десятичной точки. По умолчанию оно равно шести. Перед десятичной точкой генерируется как минимум одна цифра. Если Precision равно нулю, десятичная точка не формируется.
- 'g','G'
-
Число с плавающей точкой форматируется в формате e или f в случае g; E или F для G. Формат f используется, если порядок для формата e больше -5 и меньше Precision (точность). Precision указывает количество значащих цифр, по умолчанию шесть. Хвостовые нули после десятичной точки удаляются, а если дробная часть равна нулю, тогда десятичная точка не формируется.
- 'a','A'
-
Число с плавающей точкой форматируется в шестнадцатеричной экспоненциальной нотации 0xh.hhhhhhp±d. Присутствует одна шестнадцатеричная цифра перед точкой, и столько цифр после неё, сколько указано в параметре Precision (точность). Если Precision равно нулю, десятичная точка не формируется. Если Precision отсутствует, генерируется столько шестнадцатеричных цифр, сколько необходимо для точного представления мантиссы. В порядок записывается как можно меньше цифр, но по крайней мере одна, он является десятичным числом и представляет степень 2, как в h.hhhhhh*2±d. Порядок для нуля равен нулю. Шестнадцатеричные цифры, символы x и p находятся в верхнем регистре, если FormatChar представлен верхним регистром.
Значение NaN (не-число) для чисел с плавающей точкой форматируется как
nan, если
FormatChar представлен в нижнем регистре, или
NAN, если в верхнем. Значение бесконечности для чисел с плавающей точкой отформатируется как
inf или
infinity, если
FormatChar представлен в нижнем регистре, или
INF или
INFINITY, если в верхнем.
Пример:
import std.array : appender;
import std.format : formattedWrite;
auto writer = appender!string();
formattedWrite(writer, "%s - это окончательный %s.", 42, "ответ");
assert(writer.data == "42 - это окончательный ответ.");
writer = appender!string();
formattedWrite(writer, "Дата: %2$s %1$s", "октября", 5);
assert(writer.data == "Дата: 5 октября");
Позиционные и непозиционные стили можно смешивать в одной форматирующей строке. (POSIX оставляет это поведение неопределенным.) Внутренний счетчик для непозиционных параметров отсчитывает следующий параметр после самого большого позиционного параметра, который уже использован.
Пример использования массива и форматирования вложенных массивов:
import std.stdio;
void main()
{
writefln("Мои элементы - это %(%s %).", [1,2,3]);
writefln("Мои элементы - это %(%s, %).", [1,2,3]);
}
Результат:
Мои элементы - это 1 2 3.
Мои элементы - это 1, 2, 3.
Хвостовая часть форматирующей под-строки, следующая за спецификатором для каждого элемента, интерпретируется как разделитель массива и поэтому опускается после последнего элемента массива. Можно использовать спецификатор разделителя
%| для указания места, где начинается разделитель, таким образом часть форматирующей строки до него будет сохранена в последнем элементе массива:
import std.stdio;
void main()
{
writefln("Мои элементы - это %(-%s-%|, %).", [1,2,3]);
}
что даст на выходе:
Мои элементы - это -1-, -2-, -3-.
Эти составные спецификаторы формата можно вставлять в случае аргумента – вложенного массива:
import std.stdio;
void main() {
auto mat = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]];
writefln("%(%(%d %)\n%)", mat);
writeln();
writefln("[%(%(%d %)\n %)]", mat);
writeln();
writefln("[%([%(%d %)]%|\n %)]", mat);
writeln();
}
Выводит:
1 2 3
4 5 6
7 8 9
[1 2 3
4 5 6
7 8 9]
[[1 2 3]
[4 5 6]
[7 8 9]]
Внутри составного спецификатора формата все строки и символы автоматически экранируются. Чтобы избежать такого поведения, добавьте флаг
'-' к
"%(".
import std.stdio;
void main()
{
writefln("Мои друзья - это %s.", ["Джон", "Нэнси"]);
writefln("Мои друзья - это %(%s, %).", ["Джон", "Нэнси"]);
writefln("Мои друзья - это %-(%s, %).", ["Джон", "Нэнси"]);
}
что даст на выходе:
Мои друзья - это ["Джон", "Нэнси"].
Мои друзья - это "Джон", "Нэнси".
Мои друзья - это Джон, Нэнси.