Racket: Форматирование строк

В программировании часто возникает задача собрать строку из значений, которые не являются строками сами по себе. Для решения подобных задач применяют форматирование (formatting) строк (оно же — "строковая интерполяция"). В Racket средств для форматирования присутствует довольно много, но мы рассмотрим самые популярные.

Функции format и printf

Функции format и printf ожидают в качестве первого аргумента строку-шаблон и несколько значений, которые будут в этот шаблон подставлены. Разница же между функциями в том, что вызов format вычисляется в строку, а printf сразу выводит значение на экран (результатом же вычисления будет #<void>).

Шаблон может содержать произвольный текст, в нужные места которого вставлены следующие последовательности:

  • ~a, означающая "подставить в читаемом виде"
  • ~v, означающая "вывести как в REPL"
  • ~n, означающая "вставить перевод строки"
  • ~~, означающая "просто вывести ~"

Есть и другие последовательности, о которых можно почитать здесь, но перечисленные выше используются чаще всего.

~a используется всегда, когда нужно подставить число, строку или строковый символ. При этом в текст не попадут кавычки, обрамляющие строковый литерал и символы будут подставлены в печатаемом виде, а не в виде кода (a, вместо #\a).

~v пригодится тогда, когда нужно вывести некое комплексное значение в таком виде, в каком его отображает интерпретатор и интерактивном режиме. Этот вариант вывода очень полезен при отладке: выведенные значения часто можно скопировать в REPL или в редактор и повторно вычислить.

Назначение ~n и ~~ довольно очевидно, согласитесь?

Вот несколько примеров применения printf:

(printf "This is a list: ~v~n" '(1 2 3))
; => This is a list: '(1 2 3)
(printf "This is a string: ~v~n" "hello")
; => This is a string: "hello"
(printf "~a + ~a = ~a~n" 40 2 (+ 40 2))
; => 40 + 2 = 42
(printf "~v is \"~a\"~n" #\! #\!)
; => #\! is "!"
(printf "~v prints as \"~a\"~n" "abc" "abc")
; => "abc" prints as "abc"
(printf "~v prints as \"~a\"~n" '(42) '(42))
; => '(42) prints as "(42)"

Функции ~a, ~v

Для большинства последовательностей, работающих в шаблонах, есть аналоги в виде одноимённых функций — таких как ~a и ~v. Рассмотрим подробнее ~a, остальные же вы сможете изучить сами.

~a принимает одно или несколько значений, которые будет преобразованы в строки и объединены в результирующую строку. Кроме перечня значений функция принимает десяток опциональных именованных аргументов, таких как #:separator, #:min-width и #:align (полный список, как обычно, имеется в документации).

Вот как работают само преобразование аргументов и подстановка разделителя:

(~a 1)                      ; "1"
(~a 1 2 3)                  ; "123"
(~a 1 "+" 3)                ; "1+3"
(~a 1 2 3 #:separator ", ") ; "1, 2, 3"

#:min-width и #:align удобны для вывода чисел в столбик:

(~a 42 #:min-width 6)                 ; "42    "
(~a 42 #:min-width 6 #:align 'center) ; "  42  "
(~a 42 #:min-width 6 #:align 'right)  ; "    42"

Слова с одинарной кавычкой в начале это те самые символы, которые по-английски называются "symbols". Symbols будут рассмотрены позднее, пока можете воспринимать их как константы, означающие сами себя — более компактная и быстрая альтернатива строковым константам.

Среди аргументов ~a есть и такие, которые ограничивают максимальную длину результирующей строки, задающие то, чем заполняются отступы слева и справа. Словом, возможности широки!

Задание

Реализуйте функцию add, которая должна для двух чисел вычислить сумму в виде "сложения в столбик" (в виде строки). Ширина текста должна подстраиваться под количество разрядов в сумме. Сами аргументы считайте всегда целыми и неотрицательными.

Примеры:

(displayln (add 1 2))
; => +1
; =>  2
; =>  -
; =>  3
(displayln (add 1 9))
; => + 1
; =>   9
; =>  --
; =>  10
(displayln (add 1223234 56))
; => +1223234
; =>       56
; =>  -------
; =>  1223290

Нашли ошибку? Есть что добавить? Пулреквесты приветствуются https://github.com/hexlet-basics
Если вы столкнулись с трудностями и не знаете, что делать, задайте вопрос в нашем большом и дружном сообществе