formattazione di stringhe in stile printf


9

Sfida

Scrivi una funzione che implementa printfla formattazione di stringhe in stile C.

Regole

  1. È necessario implementare almeno %%, %c, %s, %de %f.
  2. Non è necessario utilizzare un metodo di formattazione stringa incorporato.
  3. Non è necessario eseguire programmi esterni o connettersi a Internet dal proprio programma.
  4. Sta a te decidere come gestire input non validi, ma il tuo programma non deve terminare in modo anomalo.
  5. Si dovrebbe scrivere un Funzione Variadica se possibile.

Le parole chiave "DEVE", "NON DEVE", "RICHIESTO", "DEVE ESSERE", "NON DEVE", "DOVREBBE", "NON DOVREBBE", "CONSIGLIATO", "MAGGIO" e "OPZIONALE" in questo documento sono da interpretare come descritto in RFC 2119 .


Cosa fa %c? Abbastanza sicuro %s, %de %fsono per archi, ints e float relativamente rispettosi, ma non sono sicuro %c.
Sumurai8,

%cvisualizza il valore ASCII di un int passato IIRC
Marin

Stampa il personaggio, quindi 97e 'a'diventerebbe entrambi ain uscita.
nyuszika7h,

non c'è bisogno di supportare qualche modulo come %-02dgiusto? solo che tre% c,% s,% d?
YOU

@YOU Corretto. È abbastanza.
nyuszika7h,

Risposte:


4

APL (73)

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

Alcuni test:

      '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.

Spiegazione:

  • G←'%!',⍺: prefisso un identificatore fittizio alla stringa (per un'elaborazione più semplice)
  • (Z←G='%')/⍳⍴G: trova gli indici di tutti i %caratteri nella stringa; memorizza anche una maschera di bitZ
  • ⌷∘G¨1↓1+: seleziona tutti i caratteri accanto alla %s e rilascia il manichino.
  • ⍵,⍪: abbina ogni identificatore con il suo valore dall'argomento giusto.
  • {... }/: esegue la seguente funzione su ogni coppia:
    • 'c'0≡⍵,∊⊃⍺: se l'argomento è un numero e lo specificatore è c:
    • :⎕UCS⍺: quindi restituisce il valore unicode dell'argomento,
    • ⋄⍕⍺: altrimenti, restituisce la rappresentazione in formato stringa dell'argomento.
  • : accludere
  • ⊂2∘↓¨Z⊂G: dividere la stringa su %s, quindi rimuovere i primi due caratteri di ogni sottostringa (qui entra in gioco il manichino) e racchiuderne il risultato.
  • : crea una matrice dai due array racchiusi, abbinando ciascuna sottostringa al valore che dovrebbe seguirla.
  • ,⌿: unisce ogni sottostringa al suo valore.
  • ⊃,/: quindi unisci le stringhe risultanti.

È sempre divertente vedere lingue esoteriche che sembrano incomprensibili. ;)
nyuszika7h

2
@ nyuszika7h: in realtà è un linguaggio serio. Risale agli anni '60 ed è ancora in uso. Sembrerebbe un po 'meno incomprensibile se non fosse golfato.
Marin

Vedo, interessante.
nyuszika7h,

@ nyuszika7h: Beh, tecnicamente è un linguaggio di programmazione orientato all'elenco, quindi potresti dire che è progettato per il golf del codice, soprattutto considerando che utilizza un set di caratteri speciali destinato a rendere i programmi più leggibili e meno dettagliati. Ed è stata fonte d'ispirazione per il linguaggio di programmazione J e GolfScript.
Konrad Borowski,

@xfix Pensavo che LISP fosse il linguaggio di programmazione orientato all'elenco? Abbiamo usato APL all'università per lavoro reale: essere in grado di gestire gli array in modo nativo è davvero utile. J è stato progettato da uno degli inventori di APL come suo "successore" - ovviamente questo non significa che non sia utile per il golf del codice ...
Jerry Jeremiah,

2

Rubino: 102 caratteri

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

Esecuzione di esempio:

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

Gli identificatori di formato non validi vengono mantenuti in posizione. Gli identificatori di formato senza valore argomento vengono sostituiti con il valore vuoto del tipo specificato.


È possibile fornire una funzione anonima, in modo da far cadere il leaderf
cat

Infatti. Ma come ricordo, al momento della pubblicazione di questo, le funzioni anonime non erano accettate all'unanimità. Per ora, né la risposta Lua è stata aggiornata alla funzione anonima (per salvare la stessa quantità di caratteri), penso che non avvierò la campagna di aggiornamento.
arte

2

Lua 5.2, 115 byte

-- 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

Ben fatto. Quale versione di Lua? 5.1.5 fornisce "un numero non valido vicino a" 1 ritorno ". Piccolo problema con "% c", non riesce su "N" anziché su 78. O è anche solo la peculiarità della mia vecchia Lua?
arte

@manatwork - Prova qui
Egor Skriptunoff,

Sì, ci lavora.
arte

Funziona per me su Lua 5.2.3.
nyuszika7h,

1

C ++ (281 caratteri)

#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 il C ++, ma mi è sembrata una buona scelta (andrei davvero con C, altrimenti il char*puntatore richiede troppo sforzo per essere effettivamente utile). Accetta char*argomenti e std::stringrisultati, ma ehi, questo è C ++, quindi a chi importa la coerenza (in un linguaggio che non è coerente)?


Questo non viene compilato, in quanto non ha una funzione principale.
nyuszika7h,

@ nyuszika7h: la domanda era di fare una funzione, no main. Ma se hai bisogno di un campione main, prova gist.github.com/xfix/8238576 (l'ho usato durante il test di questa funzione).
Konrad Borowski,

È vero, non puoi davvero fare una mainfunzione significativa , aggiungerne uno aumenterebbe semplicemente il conteggio dei personaggi. Se non volessi modificare il codice, potrei aggiungere un file di intestazione che lo accompagna e #includedal mio programma di test.
nyuszika7h,

1

Java , 201 186 174 byte

12 byte grazie 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;}

Provalo online!


Non ne sono del tutto sicuro, ma penso che tu possa rimuoverlo =s.charAt(0)da char c=s.charAt(0). Funziona ancora nel TIO quando lo faccio.
Kevin Cruijssen,

@KevinCruijssen Giuro che è abbastanza intelligente.
Leaky Nun,

So che è passato un po 'di tempo, ma puoi salvare altri 8 byte stampando direttamente: 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 byte (e altri convertendoli in Java 8, ma non è proprio il tuo genere, vero?)
Kevin Cruijssen
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.