formatage de chaîne de style printf

9

Défi

Écrivez une fonction qui implémente printfla mise en forme des chaînes de style C.

Règles

  1. Vous devez mettre en œuvre au moins %%, %c, %s, %det %f.
  2. Vous ne devez pas utiliser une méthode de formatage de chaîne intégrée.
  3. Vous ne devez pas exécuter de programmes externes ni vous connecter à Internet à partir de votre programme.
  4. C'est à vous de décider comment gérer les entrées invalides, mais votre programme ne doit pas se terminer anormalement.
  5. Vous devriez écrire une fonction variadique si possible.

Les mots clés "DOIT", "NE DOIT PAS", "OBLIGATOIRE", "DOIT", "NE DOIT PAS", "DEVRAIT", "NE DEVRAIENT PAS", "RECOMMANDÉ", "MAI" et "FACULTATIF" dans ce document sont à interpréter comme décrit dans la RFC 2119 .

nyuszika7h
la source
Que fait %c-il? Plutôt sûr %s, %det %fsont respectives pour les cordes, les pouces et les flotteurs, mais pas sûrs %c.
Sumurai8
%caffiche la valeur ASCII d'un entier transmis IIRC
marinus
Il imprime le caractère, donc 97et 'a'deviendrait tous les deux asur la sortie.
nyuszika7h
pas besoin de supporter une forme comme ça %-02d? juste que trois% c,% s,% d?
VOUS du
@YOU Correct. C'est assez.
nyuszika7h

Réponses:

4

APL (73)

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

Quelques tests:

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

Explication:

  • G←'%!',⍺: préfixe un spécificateur factice à la chaîne (pour un traitement plus facile)
  • (Z←G='%')/⍳⍴G: recherche les indices de tous les %caractères de la chaîne; stocker également un bitmask dansZ
  • ⌷∘G¨1↓1+: sélectionnez tous les caractères à côté du %s et déposez le mannequin.
  • ⍵,⍪: faire correspondre chaque spécificateur avec sa valeur de l'argument de droite.
  • {... }/: exécutez la fonction suivante sur chaque paire:
    • 'c'0≡⍵,∊⊃⍺: si l'argument est un nombre et que le spécificateur est c:
    • :⎕UCS⍺: retourne ensuite la valeur unicode de l'argument,
    • ⋄⍕⍺: sinon, retourne la représentation sous forme de chaîne de l'argument.
  • : joindre
  • ⊂2∘↓¨Z⊂G: divisez la chaîne sur le %s puis supprimez les deux premiers caractères de chaque sous-chaîne (c'est là que le mannequin entre en jeu), et entourez le résultat de cela.
  • : créez une matrice à partir des deux tableaux fermés, en faisant correspondre chaque sous-chaîne avec la valeur qui doit la suivre.
  • ,⌿: joindre chaque sous-chaîne avec sa valeur.
  • ⊃,/: puis joignez les chaînes résultantes.
marinus
la source
C'est toujours amusant de voir des langues ésotériques qui ressemblent à du charabia. ;)
nyuszika7h
2
@ nyuszika7h: C'est en fait un langage sérieux. Il date des années 1960 et il est toujours utilisé. Cela ressemblerait un peu moins à du charabia s'il n'était pas joué au golf.
marinus
Je vois, intéressant.
nyuszika7h
@ nyuszika7h: Eh bien, techniquement, c'est un langage de programmation orienté liste, vous pouvez donc dire qu'il est conçu pour le golf de code, d'autant plus qu'il utilise un jeu de caractères spécial destiné à rendre les programmes plus lisibles et moins verbeux. Et c'était une inspiration pour le langage de programmation J et GolfScript.
Konrad Borowski
@xfix Je pensais que LISP était le langage de programmation orienté liste? Nous avons utilisé APL à l'université pour un vrai travail - être capable de gérer des tableaux en natif est vraiment pratique. J a été conçu par l'un des inventeurs de l'APL comme son "successeur" - bien sûr, cela ne signifie pas qu'il n'est pas utile pour le golf de code ...
Jerry Jeremiah
2

Ruby: 102 caractères

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

Exemple d'exécution:

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

Les spécificateurs de format non valides sont conservés. Les spécificateurs de format sans valeur d'argument sont remplacés par la valeur vide du type donné.

homme au travail
la source
Vous pouvez fournir une fonction anonyme, alors laissez tomber le premierf
cat
En effet. Mais si je me souviens bien, au moment de la publication de ce document, les fonctions anonymes n'étaient pas acceptées à l'unanimité. Pour l'instant ni la réponse de Lua n'a été mise à jour en fonction anonyme (pour enregistrer le même nombre de caractères), je pense que je ne lancerai pas la campagne de mise à jour.
manatwork
2

Lua 5.2, 115 octets

-- 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
la source
Joli. Quelle version de Lua? 5.1.5 donne «un nombre mal formé près de« 1 retour »». Petit problème avec «% c», il échoue sur «N» au lieu de 78. Ou est-ce aussi juste la particularité de mon ancien Lua?
manatwork du
@manatwork - Essayez ici
Egor Skriptunoff
Yepp, travaille là-bas.
manatwork du
Fonctionne pour moi sur Lua 5.2.3.
nyuszika7h
1

C ++ (281 caractères)

#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();}

Je déteste le C ++, mais cela semblait être un bon choix (j'irais vraiment avec C, sinon ce char*pointeur nécessite trop d'efforts pour être réellement utile). Prend des char*arguments et des std::stringrésultats, mais bon, c'est C ++, alors qui se soucie de la cohérence (dans un langage qui lui-même n'est pas cohérent)?

Konrad Borowski
la source
Cela ne compile pas, car il n'a pas de fonction principale.
nyuszika7h
@ nyuszika7h: La question était de créer une fonction, non main. Mais si vous avez besoin d'un échantillon main, essayez gist.github.com/xfix/8238576 (j'ai utilisé celui-ci lors du test de cette fonction).
Konrad Borowski
Certes, vous ne pouvez pas vraiment créer une mainfonction significative , en ajouter une augmenterait simplement le nombre de caractères. Si je ne voulais pas modifier le code, je pourrais ajouter un fichier d'en-tête d'accompagnement et #includeà partir de mon programme de test.
nyuszika7h
1

Java , 201 186 174 octets

12 octets grâce à 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;}

Essayez-le en ligne!

Leaky Nun
la source
Je ne suis pas tout à fait sûr, mais je pense que vous pouvez supprimer =s.charAt(0)de char c=s.charAt(0). Cela fonctionne toujours dans le TIO quand je le fais.
Kevin Cruijssen
@KevinCruijssen Je jure que c'est assez intelligent.
Leaky Nun
Je sais que ça fait un moment, mais vous pouvez économiser 8 octets de plus en imprimant directement: 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 octets (et encore plus en convertissant en Java 8, mais ce n'est pas vraiment votre truc, n'est-ce pas?)
Kevin Cruijssen