stringtranslate.com

Formato (Lisp común)

Formato es una función en Common Lisp que puede producir texto formateado usando una cadena de formato similar a la cadena de formato printf . Proporciona más funcionalidad que printf, permitiendo al usuario generar números en varios formatos (incluidos, por ejemplo: hexadecimal, binario, octal, números romanos e inglés), aplicar ciertos especificadores de formato solo bajo ciertas condiciones, iterar sobre estructuras de datos, generar datos de forma tabular, e incluso recursiva, llamando formatinternamente para manejar estructuras de datos que incluyen sus propias cadenas de formato preferidas. Esto se origina funcionalmente en Lisp Machine Lisp del MIT , [1] donde se basó en Multics ioa_[ cita requerida ] .

Especificación

La formatfunción está especificada por la sintaxis [2]

formato destino  controlCadena y resto formatoArgumentos

Las directivas en la cadena de control se interpolan utilizando los argumentos de formato y la secuencia de caracteres así construida se escribe en el destino.

Destino

El destino puede ser una secuencia, una cadena dinámica To la NILconstante; el último de los cuales presenta un caso especial en el sentido de que crea, formatea y devuelve un nuevo objeto de cadena, mientras que Tse refiere a la salida estándar, que suele ser equivalente a la consola. Los flujos en Common Lisp comprenden, entre otros, salidas de cadenas y flujos de archivos; por lo tanto, al ser capaz de escribir en tal variedad de destinos, esta función unifica capacidades distribuidas entre distintos comandos en algunos otros lenguajes de programación, como C printfpara salida de consola, sprintfformato de cadenas y fprintfescritura de archivos.

La multitud de tipos de destino se ejemplifica a continuación:

;; Imprime "1 + 2 = 3" en la salida estándar y devuelve ``NIL''. ( formato T "1 + 2 = ~d" 3 )   ;; Crea y devuelve una nueva cadena que contiene "1 + 2 = 3". ( formato NIL "1 + 2 = ~d" 3 )   ;; Crea y devuelve una nueva cadena que contiene "1 + 2 = 3". ( con-salida-a-cadena ( salida ) ( formato de salida "1 + 2 = ~d" 3 ))     ;; Escribe en el archivo "outputFile.txt" la cadena "1 + 2 = 3". ( con-abrir-archivo ( salida "outputFile.txt" :dirección :salida :si-no-existe :crear :si-existe :append ) ( formatear salida "1 + 2 = ~d" 3 ))            ;; Agrega a la cadena dinámica la cadena "1 + 2 = 3". ( let (( cadena de salida ( make-array 0 : tipo de elemento 'carácter : ajustable T : puntero de relleno 0 ))) ( declarar ( tipo cadena cadena de salida )) ( formato cadena de salida "1 + 2 = ~ d" 3 ) ( la cadena de salida-cadena ))                    

Control de cadena y formato de argumentos

La cadena de control puede contener caracteres literales, así como el carácter meta ~(tilde), que delimita las directivas de formato . Mientras que los literales en la entrada se repiten palabra por palabra, las directivas producen una salida especial, que a menudo consume uno o más argumentos de formato.

Directivas

Una directiva de formato, introducida por a ~, va seguida de cero o más parámetros de prefijo, cero o más modificadores y el tipo de directiva. Por lo tanto, una definición directiva debe ajustarse al patrón

~[ parámetros de prefijo ][ modificadores ] tipo de directiva

El tipo de directiva siempre se especifica mediante un solo carácter, sin distinguir entre mayúsculas y minúsculas en el caso de letras. Los datos que una directiva de formato debe procesar, si son necesarios, se denominan argumento de formato y pueden ser cero o más objetos de cualquier tipo compatibles. Si se aceptan dichos datos y en qué cantidad depende de la directiva y de los posibles modificadores que se le apliquen. La directiva tipo ~%, por ejemplo, se abstiene del consumo de cualquier argumento de formato, mientras que ~despera que se imprima exactamente un número entero, y ~@{, una directiva influenciada por el modificador de signo de arroba, procesa todos los argumentos restantes.

La siguiente directiva, ~bespera un objeto numérico de los argumentos de formato y escribe su equivalente binario (base 2) en la salida estándar.

( formato T "~b" 5 )   

Cuando las configuraciones son permisivas, se pueden especificar parámetros de prefijo.

Parámetros de prefijo

Los parámetros de prefijo permiten una inyección de información adicional en una directiva para operar, similar a la operación de parámetros cuando se proporcionan a una función. Los parámetros de prefijo son siempre opcionales y, si se proporcionan, deben ubicarse entre el tipo de introducción ~y los modificadores o, si no hay ninguno, el tipo de directiva. Los valores están separados por comas, pero no toleran espacios en blanco a ambos lados. El número y tipo de estos parámetros depende de la directiva y de la influencia de posibles modificadores.

Se pueden utilizar dos caracteres particulares como valores de parámetros de prefijo con interpretación distintiva: vo Vactúa como marcador de posición para un número entero o carácter de los argumentos de formato que se consume y se coloca en su lugar. El segundo carácter especial, #, se sustituye por el recuento de argumentos de formato respetando su consumo. Ambos vy #habilitan el comportamiento definido por contenido dinámico inyectado en la lista de parámetros de prefijo.

El vvalor del parámetro introduce una funcionalidad equivalente a una variable en el contexto de la programación general. Dado este escenario simple, para rellenar a la izquierda una representación binaria del número entero 5con al menos ocho dígitos con ceros, la solución literal es la siguiente:

( formato T "~8,'0b" 5 )   

Sin embargo, el primer parámetro de prefijo que controla el ancho de salida puede definirse en términos del vcarácter, delegando la especificación del valor del parámetro al siguiente argumento de formato, en nuestro caso 8.

( formato T "~v,'0b" 8 5 )    

Las soluciones de este tipo son particularmente beneficiosas si partes de la lista de parámetros de prefijo se describen mediante variables o argumentos de función en lugar de literales, como es el caso en el siguiente código:

( let (( número de dígitos 8 )) ( declarar ( tipo ( entero 0 * ) número de dígitos )) ( formato T "~v,'0b" número de dígitos 5 ))             

Aún más apropiado en aquellas situaciones que involucran entrada externa, se puede pasar un argumento de función a la directiva de formato:

( defun print-as-hexadecimal ( número a formato número de dígitos ) "Imprime el NÚMERO A FORMATO en el sistema hexadecimal (base 16),  relleno a la izquierda con ceros hasta al menos el NÚMERO DE DÍGITOS. " ( declarar ( escribir número número a formatear )) ( declarar ( escribir ( entero 0 * ) número de dígitos )) ( formato T "~v,'0x" número de dígitos número a formatear ) )                   ( imprimir como hexadecimal 12 2 )  

#como parámetro de prefijo cuenta los argumentos de formato que aún no han sido procesados ​​por las directivas anteriores, y lo hace sin consumir nada de esta lista. La utilidad de un valor insertado dinámicamente está restringida predominantemente a casos de uso relacionados con el procesamiento condicional. Como el número de argumento sólo puede ser un número entero mayor o igual a cero, su significado coincide con el de un índice en las cláusulas de una ~[directiva condicional.

La interacción del #valor del parámetro de prefijo especial con la directiva de selección condicional ~[se ilustra en el siguiente ejemplo. La condición establece cuatro cláusulas, accesibles a través de los índices 0, 1, 2 y 3 respectivamente. El número de argumentos de formato se emplea como medio para la recuperación del índice de cláusulas; para hacerlo, insertamos #en la directiva condicional que permite que el índice sea un parámetro de prefijo. #calcula el recuento de argumentos de formato y sugiere este número como índice de selección. Los argumentos, no consumidos por este acto, están disponibles y procesados ​​por las directivas de la cláusula seleccionada.

;; Imprime "ninguno seleccionado". ( formato T "~#[ninguno seleccionado~;uno seleccionado: ~a~;dos seleccionados: ~a y ~a~:;más seleccionados: ~@{~a~^, ~}~]" )  ;; Imprime "uno seleccionado: BUNNY". ( formato T "~#[ninguno seleccionado~;uno seleccionado: ~a~;dos seleccionados: ~a y ~a~:;más seleccionados: ~@{~a~^, ~}~]" 'conejito )   ;; Imprime "dos seleccionados: BUNNY y PIGEON". ( formato T "~#[ninguno seleccionado~;uno seleccionado: ~a~;dos seleccionados: ~a y ~a~:;más seleccionados: ~@{~a~^, ~}~]" 'conejito 'paloma )    ;; Imprime "más seleccionados: CONEJITO, PALOMA, RATÓN". ( formato T "~#[ninguno seleccionado~;uno seleccionado: ~a~;dos seleccionados: ~a y ~a~:;más seleccionados: ~@{~a~^, ~}~]" 'conejito 'paloma ' ratón )     

Modificadores

Los modificadores actúan en calidad de banderas que pretenden influir en el comportamiento de una directiva. La admisión, la magnitud de la modificación del comportamiento y el efecto, al igual que con los parámetros de prefijo, dependen de la directiva. En algunos casos graves, la sintaxis de una directiva puede variar hasta el punto de invalidar ciertos parámetros de prefijo; este poder distingue especialmente a los modificadores de la mayoría de los parámetros. Los dos caracteres modificadores válidos son @(arroba) y :(dos puntos), posiblemente en combinación como :@o @:.

El siguiente ejemplo ilustra un caso bastante leve de influencia ejercida sobre una directiva por el @modificador: simplemente garantiza que la representación binaria de un número formateado siempre esté precedida por el signo del número:

( formato T "~@b" 5 )   

Directivas de formato

A continuación se incluye una enumeración de las directivas de formato, incluida su sintaxis completa y sus efectos modificadores. [3]

Ejemplo

Un ejemplo de una printfllamada C es el siguiente:

 printf ( "Color %s, número1 %d, número2 %05d, hexadecimal %x, flotante %5.2f, valor sin signo %u. \n " , "rojo" , 123456 , 89 , 255 , 3,14 , 250 );      

Usando Common Lisp, esto es equivalente a:

 ( formato t "Color ~A, número1 ~D, número2 ~5,'0D, hexadecimal ~X, flotante ~5,2F, valor sin signo ~D.~%" "rojo" 123456 89 255 3,14 250 ) ;; imprime: Color rojo, número1 123456, número2 00089, hexadecimal FF, flotante 3,14, valor sin signo 250.         

Otro ejemplo sería imprimir cada elemento de la lista delimitado por comas, lo que se puede hacer usando las directivas ~{ , ~^ y ~ }: [4]

 ( let (( comestibles ' ( huevos, pan , mantequilla, zanahorias ))) ( formato t "~{~A~^, ~}.~%" comestibles ) ; Imprime en mayúsculas ( formato t "~:(~{~A~^ , ~}~).~%" comestibles )) ; Capitaliza la producción ;; estampados: HUEVOS, PAN, MANTEQUILLA, ZANAHORIAS. ;; estampados: Huevos, Pan, Mantequilla, Zanahorias.                 

Tenga en cuenta que no solo se itera directamente la lista de valores format, sino que las comas se imprimen correctamente entre los elementos, no después de ellos. Un ejemplo aún más complejo sería imprimir una lista utilizando frases habituales en inglés:

( let (( plantilla "Los afortunados ganadores fueron:~#[ none~; ~S~; ~S y ~S~  ~:;~@{~#[~; and~] ~S~^,~}~] ." )) ( formato nil plantilla ) ;; ⇒ "Los afortunados ganadores fueron: ninguno." ( formato nil plantilla 'foo ) ;; ⇒ "Los afortunados ganadores fueron: FOO." ( formato nil plantilla 'foo ' bar ) ; ; ⇒ "Los afortunados ganadores fueron: FOO y BAR." ( formato nil plantilla 'foo 'bar 'baz ) ;; ⇒ "Los afortunados ganadores fueron: FOO, BAR y BAZ ( formato nil plantilla 'foo 'bar ' ". baz 'quux ) ;; ⇒ "Los afortunados ganadores fueron: FOO, BAR, BAZ y QUUX" .                                 

La capacidad de definir una nueva directiva proporciona los medios para la personalización. El siguiente ejemplo implementa una función que imprime una cadena de entrada en minúsculas, mayúsculas o estilo inverso, permitiendo también una configuración del número de repeticiones.~/functionName/

( defun mydirective ( destino formato-argumento dos puntos-modificador-supplied-p at-sign-modifier-supplied-p &opcional ( repeticiones 1 )) "Esta función representa una devolución de llamada adecuada como directiva en una  invocación de ``formato'', esperando una cadena como su FORMATO-ARGUMENTO  para imprimir REPETICIONES el número de veces al DESTINO  ---  Los indicadores COLON-MODIFIER-SUPPLIED-P y AT-SIGN-MODIFIER-SUPPLIED-P  esperan un booleano generalizado cada uno, siendo los representantes del  Modificadores ``:'' y ``@'' respectivamente. Su influencia se define  de la siguiente manera:  - Si no se establece ningún modificador, el FORMATO-ARGUMENTO se imprime sin  más modificaciones.  - Si se establece el modificador de dos puntos, pero no el arroba. -modificador de signo, el  ARGUMENTO DE FORMATO se convierte a minúsculas antes de imprimir  - Si se establece el modificador en, pero no el modificador de dos puntos, el  ARGUMENTO DE FORMATO se convierte a mayúsculas antes de imprimir  - Si se configuran ambos modificadores, el. FORMAT-ARGUMENT se invierte antes de  imprimir  ---  El número de veces que se imprimirá la cadena FORMAT-ARGUMENT está  determinado por el parámetro de prefijo REPETITIONS, que debe ser un  número entero no negativo y su valor predeterminado es uno." ( declarar ( tipo ( o nulo ( eql T ) cadena de flujo ) destino )) ( declarar ( tipo T formato-argumento )) ( declarar ( tipo T modificador de dos puntos-suministrado-p )) ( declarar ( tipo T at-sign-modificador-suministrado ) -p )) ( declarar ( escribir ( entero 0 * ) repeticiones )) ( let (( argumento de formato de cadena a imprimir )) ( declarar ( escribir cadena cadena a imprimir )) ;; Ajuste STRING-TO-PRINT según los modificadores. ( cond (( y modificador-de-dos puntos-suministrado-p en-signo-modificador-suministrado-p ) ( setf string-to-print (                                                     cadena inversa para imprimir ))) ( modificador de dos puntos suministrado-p ( setf cadena para imprimir ( cadena en minúscula cadena para imprimir ))) ( modificador de signo de arroba suministrado-p ( setf cadena- to-print ( string-upcase string-to-print ))) ( T NIL )) ( repeticiones de repetición de bucle do ( formato de destino "~a" string-to-print ))))                      ;; Imprime "Hola" una sola vez. ( formato T "~/midirectiva/" "Hola" )   ;; Imprime "Hola" tres veces. ( formato T "~3/midirectiva/" "Hola" )   ;; Imprime un "Hola" en minúscula (= "hola") tres veces. ( formato T "~3:/midirectiva/" "Hola" )   ;; Imprime un "Hola" en mayúscula (= "HOLA") tres veces. ( formato T "~3@/midirectiva/" "Hola" )   ;; Imprime un "Hola" invertido (= "olleH") tres veces. ( formato T "~3:@/midirectiva/" "Hola" )   

Si bien formates algo infame por su tendencia a volverse opaco y difícil de leer, proporciona una sintaxis notablemente concisa pero poderosa para una necesidad común y especializada. [4]

Está disponible una tabla de resumen FORMAT de Common Lisp. [5]

Referencias

  1. ^ "Manual de la máquina Lisp" (PDF) . pag. 85 . Consultado el 7 de junio de 2024 .
  2. ^ "CLHS: Función FORMATO". www.lispworks.com .
  3. ^ "CLHS: Sección 22.3". www.lispworks.com .
  4. ^ ab 18. Algunas recetas de FORMATO de Practical Common Lisp
  5. ^ Tabla de resumen de FORMATO de Common Lisp

Libros