formatação de string no estilo printf

9

Desafio

Escreva uma função que implemente a printfformatação de string no estilo C.

Regras

  1. Você deve implementar pelo menos %%, %c, %s, %de %f.
  2. Você não deve usar um método de formatação de string interno.
  3. Você não deve executar programas externos ou conectar-se à Internet a partir do seu programa.
  4. Cabe a você decidir como lidar com entradas inválidas, mas seu programa não deve terminar de forma anormal.
  5. Você deve escrever uma função variável, se possível.

As palavras-chave "DEVEM", "NÃO DEVEM", "NECESSÁRIO", "DEVEM", "NÃO DEVEM", "DEVEM", "NÃO DEVEM", "RECOMENDADO", "PODE" e "OPCIONAL" neste documento são para ser interpretado como descrito na RFC 2119 .

nyuszika7h
fonte
O que %cfaz? Certamente %s, %de %fsão para strings, ints e floats respectivamente, mas não tenho certeza %c.
precisa saber é o seguinte
%cexibe o valor ASCII de um passado-in int IIRC
marinus
Ele imprime o caractere, portanto, 97e 'a'ambos ficam ana saída.
precisa saber é o seguinte
não há necessidade de apoiar alguma forma como %-02dcerto? apenas esses três% c,% s,% d?
VOCÊ
@YOU Correto. É o bastante.
precisa saber é o seguinte

Respostas:

4

APL (73)

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

Alguns testes:

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

Explicação:

  • G←'%!',⍺: prefixa um especificador fictício à string (para facilitar o processamento)
  • (Z←G='%')/⍳⍴G: encontre os índices de todos os %caracteres na string; Também armazene uma máscara de bit emZ
  • ⌷∘G¨1↓1+: selecione todos os caracteres ao lado de se %solte o manequim.
  • ⍵,⍪: combine cada especificador com seu valor no argumento correto.
  • {... }/: execute a seguinte função em cada par:
    • 'c'0≡⍵,∊⊃⍺: se o argumento for um número e o especificador for c:
    • :⎕UCS⍺: retorne o valor unicode do argumento,
    • ⋄⍕⍺: caso contrário, retorne a representação em cadeia do argumento.
  • : delimitar
  • ⊂2∘↓¨Z⊂G: divida a sequência nos se, em %seguida, remova os dois primeiros caracteres de cada substring (é aqui que o manequim entra) e inclua o resultado disso.
  • : crie uma matriz com as duas matrizes incluídas, correspondendo cada substring com o valor que deve segui-lo.
  • ,⌿: junte cada substring com seu valor.
  • ⊃,/: em seguida, junte as strings resultantes.
marinus
fonte
É sempre divertido ver idiomas esotéricos que parecem bobos. ;)
nyuszika7h
2
@ nyuszika7h: Esta é realmente uma linguagem séria. Data da década de 1960 e ainda está em uso. Seria um pouco menos sem sentido se não fosse jogado.
marinus
Entendo, interessante.
usar o seguinte código
@ nyuszika7h: Bem, tecnicamente, é uma linguagem de programação orientada a lista, então você poderia dizer que foi projetada para o código de golfe, especialmente considerando que usa um conjunto de caracteres especiais para tornar os programas mais legíveis e menos detalhados. E foi uma inspiração para a linguagem de programação J e o GolfScript.
precisa saber é o seguinte
@xfix Eu pensei que LISP era a linguagem de programação orientada a lista? Usamos o APL na universidade para um trabalho real - ser capaz de lidar com matrizes nativamente é realmente útil. J foi desenhado por um dos inventores do APL como seu "sucessor" - é claro que isso não significa que não é útil para o golfe código ...
Jerry Jeremias
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$&}}

Exemplo de execução:

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

Especificadores de formato inválidos são mantidos no lugar. Especificadores de formato sem valor de argumento são substituídos pelo valor vazio do tipo especificado.

homem a trabalhar
fonte
Você pode fornecer uma função anônima, então largue o líderf
cat
De fato. Mas, como me lembro, no momento da publicação, as funções anônimas não eram aceitas por unanimidade. Por enquanto, nem a resposta de Lua foi atualizada para a função anônima (para salvar a mesma quantidade de caracteres), acho que não vou iniciar a campanha de atualização.
Manatwork 21/03
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
fonte
Agradável. Qual versão do Lua? 5.1.5 fornece "número incorreto próximo a '1retorno'". Pequeno problema com "% c", falha em 'N' em vez de 78. Ou também é apenas a peculiaridade de minha antiga Lua?
manatwork
@manatwork - Tente aqui
Egor Skriptunoff
Sim, trabalha lá.
2010 '13
Funciona para mim no Lua 5.2.3.
precisa saber é o seguinte
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();}

Eu odeio C ++, mas parecia uma boa escolha (eu realmente escolheria C, senão esse char*ponteiro exige muito esforço para ser realmente útil). Recebe char*argumentos e std::stringresulta, mas ei, isso é C ++, então quem se importa com consistência (em uma linguagem que não é consistente)?

Konrad Borowski
fonte
Isso não compila, pois não tem uma função principal.
precisa saber é o seguinte
@ nyuszika7h: A questão era sobre criar uma função, não main. Mas se você precisar de amostra main, tente gist.github.com/xfix/8238576 (usei esse enquanto testava essa função).
precisa saber é o seguinte
É verdade que você não pode realmente fazer uma mainfunção significativa , adicionar uma apenas aumentaria a contagem de caracteres. Se não quisesse modificar o código, poderia adicionar um arquivo de cabeçalho que o acompanha e #includea partir do meu programa de teste.
precisa saber é o seguinte
1

Java , 201 186 174 bytes

12 bytes graças 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;}

Experimente online!

Freira Furada
fonte
Eu não estou totalmente certo, mas acho que você pode remover =s.charAt(0)a partir char c=s.charAt(0). Ainda funciona no TIO quando faço isso.
Kevin Cruijssen
@KevinCruijssen Eu juro que é bastante inteligente.
Leaky Nun
Eu sei que tem sido um tempo, mas você pode economizar mais 8 bytes imprimindo 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 (e um pouco mais através da conversão para Java 8, mas isso não é realmente sua coisa, não é?)
Kevin Cruijssen