formato de cadena de estilo printf

9

Desafío

Escriba una función que implemente el printfformato de cadena de estilo C.

Reglas

  1. Usted debe implementar al menos %%, %c, %s, %dy %f.
  2. No debe utilizar un método de formateo de cadena incorporado.
  3. No debe ejecutar programas externos ni conectarse a Internet desde su programa.
  4. Depende de usted decidir cómo manejar la entrada no válida, pero su programa no debe finalizar de manera anormal.
  5. Usted debe escribir una función variadic si es posible.

Las palabras clave "DEBE", "NO DEBE", "REQUERIDO", "DEBE", "NO DEBE", "DEBE", "NO DEBE", "RECOMENDARSE", "PUEDE" y "OPCIONAL" en este documento. para ser interpretado como se describe en RFC 2119 .

nyuszika7h
fuente
¿Qué %chacer? Bastante seguro %s, %dy %fson para cadenas, ints y flotadores respectivamente, pero no estoy seguro %c.
Sumurai8
%cmuestra el valor ASCII de un int IIRC pasado
marinus
Imprime el carácter, por lo tanto , 97y 'a'ambos se convertirán aen la salida.
nyuszika7h
no es necesario admitir alguna forma como la %-02dcorrecta? solo eso tres% c,% s,% d?
USTED
@YOU Correcto. Eso es suficiente.
nyuszika7h

Respuestas:

4

APL (73)

{⊃,/,⌿↑(⊂2∘↓¨Z⊂G),⊂{'c'0≡⍵,∊⊃⍺:⎕UCS⍺⋄⍕⍺}/⍵,⍪⌷∘G¨1↓1+(Z←G='%')/⍳⍴G←'%!',⍺}

Algunas pruebas:

      'a:%c b:%s c:%d'{⊃,/,⌿↑(⊂2∘↓¨Z⊂G),⊂{'c'0≡⍵,∊⊃⍺:⎕UCS⍺⋄⍕⍺}/⍵,⍪⌷∘G¨1↓1+(Z←G='%')/⍳⍴G←'%!',⍺} 65 'foo' 67
a:A b:foo c:67 

      printf←{⊃,/,⌿↑(⊂2∘↓¨Z⊂G),⊂{'c'0≡⍵,∊⊃⍺:⎕UCS⍺⋄⍕⍺}/⍵,⍪⌷∘G¨1↓1+(Z←G='%')/⍳⍴G←'%!',⍺}
      '1:%s 2:%s 3:%d 4:%c 5:%c' printf 'foo' 'bar' 100 110 'z'
1:foo 2:bar 3:100 4:n 5:z   
      'The %s brown %c%c%c jumps over the %s dog.' printf 'quick' 102 111 'x' 'lazy'
The quick brown fox jumps over the lazy dog.

Explicación:

  • G←'%!',⍺: prefija un especificador ficticio a la cadena (para un procesamiento más fácil)
  • (Z←G='%')/⍳⍴G: encuentra los índices de todos los %caracteres en la cadena; También almacenar una máscara de bits enZ
  • ⌷∘G¨1↓1+: seleccione todos los caracteres al lado de la %s, y suelte el maniquí.
  • ⍵,⍪: empareja cada especificador con su valor del argumento correcto.
  • {... }/: ejecuta la siguiente función en cada par:
    • 'c'0≡⍵,∊⊃⍺: si el argumento es un número y el especificador es c:
    • :⎕UCS⍺: luego devuelve el valor unicode del argumento,
    • ⋄⍕⍺: de lo contrario, devuelve la representación de cadena del argumento.
  • : encerrar
  • ⊂2∘↓¨Z⊂G: divide la cadena en %s y luego elimina los dos primeros caracteres de cada subcadena (aquí es donde entra el ficticio) y encierra el resultado de eso.
  • : crea una matriz con las dos matrices encerradas, haciendo coincidir cada subcadena con el valor que debería seguir.
  • ,⌿: une cada subcadena con su valor.
  • ⊃,/: luego une las cadenas resultantes.
marinus
fuente
Siempre es divertido ver idiomas esotéricos que parecen galimatías. ;)
nyuszika7h
2
@ nyuszika7h: Este es realmente un lenguaje serio. Data de la década de 1960 y todavía está en uso. Se vería un poco menos como galimatías si no fuera golf.
marinus
Ya veo, interesante.
nyuszika7h
@ nyuszika7h: Bueno, técnicamente es un lenguaje de programación orientado a listas, por lo que se podría decir que está diseñado para el golf de código, especialmente teniendo en cuenta que usa un conjunto de caracteres especial destinado a hacer que los programas sean más legibles y menos detallados. Y fue una inspiración para el lenguaje de programación J y GolfScript.
Konrad Borowski el
@xfix ¿Pensé que LISP era el lenguaje de programación orientado a la lista? Usamos APL en la universidad para un trabajo real: ser capaz de manejar matrices de forma nativa es realmente útil. J fue diseñado por uno de los inventores de APL como su "sucesor", por supuesto, eso no significa que no sea útil para el golf de código ...
Jerry Jeremiah
2

Ruby: 102 caracteres

f=->s,*a{s.gsub(/%(.)/){$1==?%??%:a.shift.send({?c=>:chr,?s=>:to_s,?d=>:to_i,?f=>:to_f}[$1])rescue$&}}

Ejecución de muestra:

irb(main):001:0> f=->s,*a{s.gsub(/%(.)/){$1==?%??%:a.shift.send({?c=>:chr,?s=>:to_s,?d=>:to_i,?f=>:to_f}[$1])rescue$&}}
=> #<Proc:0x96634ac@(irb):1 (lambda)>

irb(main):002:0> puts f["percent : %%\n   char : %c or %c\n string : %s or %s or %s\ndecimal : %d or %d or %d\n  float : %f or %f or %f\ninvalid : %x or %s or %d or %f", 65, 'B', 'format me', 42, Math::PI, 42, Math::PI, '2014', 42, Math::PI, '2014', 'more']
percent : %
   char : A or B
 string : format me or 42 or 3.141592653589793
decimal : 42 or 3 or 2014
  float : 42.0 or 3.141592653589793 or 2014.0
invalid : %x or  or 0 or 0.0
=> nil

Los especificadores de formato no válidos se mantienen en su lugar. Los especificadores de formato sin valor de argumento se reemplazan con el valor vacío del tipo dado.

hombre trabajando
fuente
Puede proporcionar una función anónima, así que suelte el mensaje principalf
cat
En efecto. Pero como recuerdo, al momento de publicar esto, las funciones anónimas no fueron aceptadas por unanimidad. Por ahora, ni la respuesta de Lua se actualizó a la función anónima (para guardar la misma cantidad de caracteres), creo que no comenzaré la campaña de actualización.
manatwork
2

Lua 5.2, 115 bytes

-- Function definition, 115 chars
function f(f,...)n,t=0,{...}return(f:gsub('%%(%a)',function(s)n=n+1return(({c=s.char})[s]or tostring)(t[n])end))end

-- Usage example
print(f('Happy %cew %d %s %f',78,2014,'Year!',math.pi))
-- Output: Happy New 2014 Year! 3.1415926535898
Egor Skriptunoff
fuente
Buena esa. ¿Qué versión de Lua? 5.1.5 da "número mal formado cerca de '1return'". Pequeño problema con "% c", falla en 'N' en lugar de 78. ¿O también es solo la peculiaridad de mi viejo Lua?
manatwork
@manatwork - Pruébalo aquí
Egor Skriptunoff
Sí, trabaja allí.
manatwork
Funciona para mí en Lua 5.2.3.
nyuszika7h
1

C ++ (281 caracteres)

#include<sstream>
#include<cstdarg>
#define q(x)va_arg(v,x);break;case
std::string p(char*f,...){std::ostringstream r;va_list v;va_start(v,f);while(*f)if(*f=='%')switch(++f,*f++){case's':r<<q(char*)'d':r<<q(int)'c':r<<(char)q(int)'%':r<<'%';}else r<<*f++;va_end(v);return r.str();}

Odio C ++, pero parecía una buena opción (realmente iría con C, si no ese char*puntero requiere demasiado esfuerzo para ser realmente útil). Toma char*argumentos y std::stringresultados, pero bueno, eso es C ++, entonces, ¿a quién le importa la consistencia (en un lenguaje que en sí mismo no es consistente)?

Konrad Borowski
fuente
Esto no se compila, ya que no tiene una función principal.
nyuszika7h
@ nyuszika7h: La pregunta era sobre hacer una función, no main. Pero si necesita una muestra main, pruebe gist.github.com/xfix/8238576 (usé esa mientras probaba esta función).
Konrad Borowski el
Es cierto que realmente no puede hacer una mainfunción significativa , agregar una solo aumentaría el recuento de caracteres. Si no quisiera modificar el código, podría agregar un archivo de encabezado adjunto y #includedesde mi programa de prueba.
nyuszika7h
1

Java , 201 186 174 bytes

12 bytes gracias a Kevin Cruijssen

String f(String s,Object...a){String r="";for(char c,i=0,j=0;i<s.length();r+=c==37?(c=s.charAt(i++))<38?c:c==99?(char)(int)a[j++]:a[j++]:c==37?"":c)c=s.charAt(i++);return r;}

Pruébalo en línea!

Monja permeable
fuente
No estoy del todo seguro, pero creo que se puede extraer =s.charAt(0)de char c=s.charAt(0). Todavía funciona en el TIO cuando lo hago.
Kevin Cruijssen
@KevinCruijssen Juro que es bastante inteligente.
Leaky Nun
Sé que ha pasado un tiempo, pero puede ahorrar 8 bytes más imprimiendo directamente: void f(String s,Object...a){for(char c,i=0,j=0;i<s.length();System.out.print(c==37?(c=s.charAt(i++))<38?c:c==99?(char)(int)a[j++]:a[j++]:c==37?"":c))c=s.charAt(i++);} 166 bytes (y algo más al convertir a Java 8, pero eso no es lo suyo, ¿verdad?)
Kevin Cruijssen