stringtranslate.com

Формат (Common Lisp)

Format — это функция в Common Lisp , которая может создавать форматированный текст с использованием строки формата,похожей на строку формата печати . Она обеспечивает большую функциональность, чемprint, позволяя пользователю выводить числа в различных форматах (включая, например: шестнадцатеричный , двоичный , восьмеричный , римские цифры и английский ), применять определенные спецификаторы формата только при определенных условиях, выполнять итерации по структурам данных , выводить данные в табличном виде и даже рекурсировать , вызываяformatвнутренне для обработки структур данных , которые включают их собственные предпочтительные строки форматирования . Эта функция берет свое начало в Lisp Machine Lisp MIT , [ 1] где она была основана на Multics .

Спецификация

Функция formatзадается следующим синтаксисом : [2]

формат назначения  controlString &rest formatArguments

Директивы в управляющей строке интерполируются с использованием аргументов формата, и сформированная таким образом последовательность символов записывается в место назначения.

Место назначения

Местом назначения может быть поток , динамическая строка , Tили NILконстанта; последний из которых представляет собой особый случай, поскольку он создает, форматирует и возвращает новый строковый объект , при этом Tссылаясь на стандартный вывод , обычно эквивалентный консоли . Потоки в Common Lisp охватывают, среди прочего, строковый вывод и файловые потоки; следовательно, будучи способной записывать в такое множество мест назначения, эта функция объединяет возможности, распределенные между различными командами в некоторых других языках программирования , таких как C для консольного вывода, для форматирования строк и для записи файлов.printfsprintffprintf

Множество типов мест назначения можно проиллюстрировать следующим образом:

;; Выводит "1 + 2 = 3" на стандартный вывод и возвращает ``NIL''. ( format t "1 + 2 = ~D" 3 )   ;; Создает и возвращает новую строку, содержащую "1 + 2 = 3". ( формат nil "1 + 2 = ~D" 3 )   ;; Создает и возвращает новую строку, содержащую "1 + 2 = 3". ( with-output-to-string ( output ) ( format output "1 + 2 = ~D" 3 ))     ;; Записывает в файл "outputFile.txt" строку "1 + 2 = 3". ( with-open-file ( output "outputFile.txt" :direction :output :if-does-not-exist :create :if-exists :append ) ( format output "1 + 2 = ~D" 3 ))            ;; Добавляет к динамической строке строку "1 + 2 = 3". ( let (( output-string ( make-array 0 :element-type 'character :adjustable t :fill-pointer 0 ))) ( declare ( type string output-string )) ( format output-string "1 + 2 = ~D" 3 ) ( the string output-string ))                    

Аргументы управляющей строки и формата

Управляющая строка может содержать литеральные символы, а также метасимвол ~ ( тильда ), который разграничивает директивы формата . В то время как литералы во входных данных отображаются дословно, директивы создают специальный вывод, часто потребляющий один или несколько аргументов формата .

Директивы

Директива формата , представленная с помощью ~, сопровождается нулем или более префиксных параметров , нулем или более модификаторов и типом директивы. Определение директивы, следовательно, должно соответствовать следующему шаблону:

~[ prefixParameters ][ modifiers ] directiveType

Тип директивы всегда указывается одним символом, нечувствительным к регистру в случае букв. Данные , которые должны быть обработаны директивой формата, если это вообще необходимо, называются ее аргументом формата и могут быть нулем или более объектов любого совместимого типа. Будут ли приняты такие данные и в каком количестве, зависит от директивы и потенциальных модификаторов, примененных к ней. ~%Например, тип директивы воздерживается от потребления любых аргументов формата, тогда как ожидает вывода ~Dровно одного целого числа~@{ , а директива, на которую влияет модификатор at-sign, обрабатывает все оставшиеся аргументы.

Следующая директива ~Bожидает один числовой объект из аргументов формата и записывает его двоичный ( основание 2) эквивалент в стандартный вывод .

( формат t "~B" 5 )   

Если конфигурации допускают это, можно указать параметры префикса.

Параметры префикса

Префиксные параметры позволяют вводить дополнительную информацию в директиву для работы, аналогично работе параметров , предоставляемых функции . Префиксные параметры всегда являются необязательными и, если они предоставляются, должны располагаться между вводным ~и либо модификаторами, либо, если их нет, типом директивы. Значения разделяются запятыми, но не допускают пробелов с обеих сторон. Количество и тип этих параметров зависят от директивы и влияния потенциальных модификаторов.

Два конкретных символа могут использоваться в качестве значений параметров префикса с отличительной интерпретацией: vили Vдействует как заполнитель для целого числа или символа из аргументов формата, который потребляется и помещается вместо него. Второй специальный символ, #, заменяется подсчетом аргументов формата, но при этом соблюдает их потребление. Оба Vи #включают поведение, определяемое динамическим содержимым, введенным в список параметров префикса.

Значение параметра Vвводит функциональность, эквивалентную переменной в контексте общего программирования. Учитывая этот простой сценарий, для того, чтобы дополнить слева двоичное представление целого числа 5по крайней мере до восьми цифр нулями, буквальное решение выглядит следующим образом:

( формат т "~8,'0b" 5 )   

Однако первый префиксный параметр, управляющий шириной вывода, может быть определен в терминах Vсимвола, делегируя спецификацию значения параметра следующему аргументу формата, в нашем случае 8.

( формат t "~v,'0b" 8 5 )    

Решения такого рода особенно полезны, если части списка параметров префикса описываются переменными или аргументами функций , а не литералами, как в следующем фрагменте кода:

( пусть (( количество-цифр 8 )) ( объявляем ( тип ( целое 0 * ) количество-цифр )) ( формат t "~V,'0b" количество-цифр 5 ))             

Еще более уместно в ситуациях, связанных с внешним вводом, передать аргумент функции в директиву формата:

( defun print-as-hexadecimal ( number-to-format number-of-digits ) "Печатает ЧИСЛО-ДЛЯ-ФОРМАТА в шестнадцатеричной системе счисления (основание 16),  дополненное слева нулями до не менее ЧИСЛА-ЦИФР." ( declare ( type number number-to-format )) ( declare ( type ( integer 0 * ) number-of-digits )) ( format t "~V,'0x" number-of-digits number-to-format ))                   ( распечатать-как-шестнадцатеричное- 12 2 )  

#как параметр префикса подсчитывает те аргументы формата, которые еще не обработаны предыдущими директивами, делая это без фактического потребления чего-либо из этого списка. Полезность такого динамически вставленного значения преимущественно ограничена случаями использования, относящимися к условной обработке. Поскольку номер аргумента может быть только целым числом, большим или равным нулю, его значимость совпадает со значимостью индекса в пунктах условной директивы ~[.

Взаимодействие специального #значения параметра префикса с директивой условного выбора ~[проиллюстрировано в следующем примере. Условие устанавливает четыре предложения, доступные через индексы 0, 1, 2 и 3 соответственно. Количество аргументов формата используется как средство для извлечения индекса предложения; для этого мы вставляем #в условную директиву, которая позволяет индексу быть параметром префикса. #вычисляет количество аргументов формата и предлагает это число в качестве индекса выбора. Аргументы, не использованные этим действием, затем доступны и обрабатываются директивами выбранного предложения.

;; Печатает "ничего не выбрано". ( формат t "~#[ничего не выбрано~;один выбран: ~A~;два выбранных: ~A и ~A~:;еще выбрано: ~@{~A~^, ~}~]" )  ;; Печатает "выбран один: КРОЛИК". ( формат t "~#[не выбрано~;выбран один: ~A~;выбрано два: ~A и ~A~:;выбрано еще: ~@{~A~^, ~}~]" 'кролик )   ;; Печатает "выбрано два: КРОЛИК и ГОЛУБЬ". ( формат t "~#[не выбрано~;выбран один: ~A~;выбрано два: ~A и ~A~:;выбрано еще: ~@{~A~^, ~}~]" ' кролик ' голубь )    ;; Печатает "еще выбрано: КРОЛИК, ГОЛУБЬ, МЫШЬ". ( формат t "~#[ничего не выбрано~;один выбран: ~A~;два выбрано: ~A и ~A~:;еще выбрано: ~@{~A~^, ~}~]" ' кролик ' голубь 'мышь )     

Модификаторы

Модификаторы действуют в качестве флагов, намереваясь повлиять на поведение директивы. Допуск, величина поведенческой модификации и эффект, как и в случае с префиксными параметрами , зависят от директивы. В некоторых серьезных случаях синтаксис директивы может быть изменен до такой степени, что некоторые префиксные параметры станут недействительными; эта сила особенно отличает модификаторы от большинства параметров. Два допустимых символа модификатора — это @(at-sign) и :(colon), возможно, в комбинации как :@или @:.

Следующий пример иллюстрирует довольно мягкий случай влияния модификатора на директиву @: он просто гарантирует, что двоичному представлению отформатированного числа всегда предшествует знак числа:

( формат t "~@B" 5 )   

Директивы форматирования

Перечень директив формата, включая их полный синтаксис и эффекты модификаторов, приведен ниже. [3]

Пример

Пример printf вызова C следующий:

 printf ( "Цвет %s, число1 %d, число2 %05d, шестнадцатеричное %x, число с плавающей точкой %5.2f, беззнаковое значение %u. \n " , "красный" , 123456 , 89 , 255 , 3.14 , 250 );      

Используя Common Lisp, это эквивалентно следующему:

 ( format t "Цвет ~A, число1 ~D, число2 ~5,'0D, шестнадцатеричное ~X, число с плавающей точкой ~5,2F, беззнаковое значение ~D.~%" " красный" 123456 89 255 3,14 250 ) ;; выводит: Цвет красный, число1 123456, число2 00089, шестнадцатеричное FF, число с плавающей точкой 3,14, беззнаковое значение 250.         

Другим примером может быть вывод каждого элемента списка, разделенного запятыми, что можно сделать с помощью директив ~{ , ~^ и ~ }: [4]

 ( let (( продукты ' ( яйца хлеб масло морковь ))) ( format t "~{~A~^, ~}.~%" продукты ) ; Печатает заглавными буквами ( format t "~:(~{~A~^, ~}~).~%" продукты )) ; Делает вывод заглавными буквами ;; печатает: ЯЙЦА, ХЛЕБ, МАСЛО, МОРКОВЬ. ;; печатает: Яйца, Хлеб, Масло, Морковь.                 

Обратите внимание, что не только список значений итерируется напрямую с помощью format, но и запятые правильно печатаются между элементами, а не после них. Еще более сложным примером будет распечатка списка с использованием общепринятой английской фразировки:

( let (( template "Счастливыми победителями стали:~#[ none~; ~S~; ~S и ~S~  ~:;~@{~#[~; и~] ~S~^,~}~]." )) ( format nil template ) ;; ⇒ "Счастливыми победителями стали: none." ( format nil template 'foo ) ;; ⇒ "Счастливыми победителями стали: FOO." ( format nil template 'foo 'bar ) ;; ⇒ "Счастливыми победителями стали: FOO и BAR." ( format nil template 'foo 'bar 'baz ) ;; ⇒ "Счастливыми победителями стали: FOO, BAR и BAZ." ( format nil template 'foo 'bar 'baz 'quux ) ;; ⇒ "Счастливыми победителями стали: FOO, BAR, BAZ и QUUX." )                                 

Возможность определения новой директивы через предоставляет средства для настройки. Следующий пример реализует функцию, которая печатает входную строку либо в нижнем регистре, либо в верхнем регистре, либо в обратном стиле, позволяя также настраивать количество повторений.~/functionName/

( defun mydirective ( destination format-argument colon-modifier-supplied-p at-sign-modifier-supplied-p &optional ( repeats 1 )) "Эта функция представляет собой обратный вызов, подходящий в качестве директивы в  вызове ``format'', ожидающий строку в качестве ФОРМАТ-АРГУМЕНТА  для печати REPETITIONS количество раз в НАЗНАЧЕНИЕ.  ---  Флаги COLON-MODIFIER-SUPPLIED-P и AT-SIGN-MODIFIER-SUPPLIED-P  ожидают обобщенное логическое значение каждый, являясь представителями модификаторов  ``:'' и ``@'' соответственно. Их влияние определяется  следующим образом:  - Если модификатор не установлен, ФОРМАТ-АРГУМЕНТ печатается без  дальнейших изменений.  - Если установлен модификатор двоеточия, но не модификатор at-sign,  ФОРМАТ-АРГУМЕНТ преобразуется в нижний регистр перед печатью.  - Если установлен модификатор at-modifier, но не модификатор colon-modifier,  FORMAT-ARGUMENT преобразуется в верхний регистр перед печатью.  - Если установлены оба модификатора, FORMAT-ARGUMENT переворачивается перед  печатью.  ---  Количество раз, которое должна быть напечатана строка FORMAT-ARGUMENT, определяется  префиксным параметром REPETITIONS, который должен быть  неотрицательным целым числом и по умолчанию равен одному." ( declare ( type ( or null ( eql t ) stream string ) destination )) ( declare ( type t format-argument )) ( declare ( type t colon-modifier-supplied-p )) ( declare ( type t at-sign-modifier-supplied-p )) ( declare ( type ( integer 0 * ) repeats )) ( let (( string-to-print format-argument )) ( declare ( type string string-to-print )) ;; Настройте STRING-TO-PRINT на основе модификаторов. ( cond (( and colon-modifier-supplied-p at-sign-modifier-supplied-p ) ( setf string-to-print (                                                     обратная строка-для-печати ))) ( двоеточие-модификатор-предоставлен-p ( setf строка-для-печати ( string-downcase строка-для-печати ))) ( at-sign-модификатор-предоставлен-p ( setf строка-для-печати ( string-upcase строка-для-печати ))) ( t nil )) ( цикл повтор повторения сделать ( назначение формата "~A" строка-для-печати ))))                      ;; Вывести "Hello" один раз. ( формат t "~/mydirective/" "Hello" )   ;; Напечатать "Hello" три раза. ( формат t "~3/mydirective/" "Hello" )   ;; Напечатайте строчную букву "Hello" (= "hello") три раза. ( format t "~3:/mydirective/" "Hello" )   ;; Напечатайте заглавную букву "Hello" (= "HELLO") три раза. ( формат t "~3@/mydirective/" "Hello" )   ;; Напечатать перевернутое "Hello" (= "olleH") три раза. ( формат t "~3:@/mydirective/" "Hello" )   

Хотя formatон и печально известен своей тенденцией становиться непрозрачным и трудным для чтения, он обеспечивает удивительно лаконичный, но мощный синтаксис для специализированных и общих потребностей. [4]

Доступна сводная таблица Common Lisp FORMAT. [5]

Смотрите также

Ссылки

  1. ^ "Lisp Machine Manual" (PDF) . стр. 85 . Получено 7 июня 2024 .
  2. ^ "CLHS: ФОРМАТ функции". www.lispworks.com .
  3. ^ "CLHS: Раздел 22.3". www.lispworks.com .
  4. ^ ab 18. Несколько рецептов ФОРМАТА из Practical Common Lisp
  5. ^ Сводная таблица Common Lisp FORMAT

Книги