format string gaya printf

9

Tantangan

Tulis fungsi yang mengimplementasikan printfpemformatan string gaya- C .

Aturan

  1. Anda harus menerapkan setidaknya %%, %c, %s, %ddan %f.
  2. Anda tidak boleh menggunakan metode pemformatan string bawaan.
  3. Anda tidak boleh menjalankan program eksternal atau terhubung ke Internet dari program Anda.
  4. Terserah Anda untuk memutuskan bagaimana menangani input yang tidak valid, tetapi program Anda tidak boleh berhenti secara tidak normal.
  5. Anda harus menulis fungsi variadik jika memungkinkan.

Kata kunci "HARUS", "HARUS TIDAK", "DIPERLUKAN", "AKAN", "TIDAK AKAN", "HARUS TIDAK", "HARUS TIDAK", "DIREKOMENDASIKAN", "MUNGKIN", dan "OPTIONAL" dalam dokumen ini adalah untuk ditafsirkan seperti yang dijelaskan dalam RFC 2119 .

nyuszika7h
sumber
Apa yang %charus dilakukan Cukup yakin %s, %ddan %funtuk string, int dan mengapung dengan hormat, tetapi tidak yakin %c.
Sumurai8
%cmenampilkan nilai ASCII dari int IIRC yang lewat
marinus
Ini mencetak karakter, jadi 97dan 'a'keduanya akan menjadi apada output.
nyuszika7h
tidak perlu mendukung beberapa bentuk seperti itu %-02dkan? Hanya tiga% c,% s,% d?
ANDA
@ YOU Benar. Cukup.
nyuszika7h

Jawaban:

4

APL (73)

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

Beberapa tes:

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

Penjelasan:

  • G←'%!',⍺: awali specifier dummy ke string (untuk memudahkan pemrosesan)
  • (Z←G='%')/⍳⍴G: temukan indeks semua %karakter dalam string; juga menyimpan bitmask diZ
  • ⌷∘G¨1↓1+: pilih semua karakter di sebelah huruf %s, dan jatuhkan boneka.
  • ⍵,⍪: cocokkan setiap specifier dengan nilainya dari argumen yang tepat.
  • {... }/: jalankan fungsi berikut pada setiap pasangan:
    • 'c'0≡⍵,∊⊃⍺: jika argumennya adalah angka dan specifiernya adalah c:
    • :⎕UCS⍺: lalu kembalikan nilai unicode argumen,
    • ⋄⍕⍺: jika tidak, kembalikan representasi string argumen.
  • : melampirkan
  • ⊂2∘↓¨Z⊂G: pisahkan string pada %s dan kemudian hapus dua karakter pertama dari masing-masing substring (ini adalah tempat dummy masuk), dan lampirkan hasilnya.
  • : buat matriks dari dua array terlampir, sesuaikan setiap substring dengan nilai yang harus mengikutinya.
  • ,⌿: gabungkan setiap substring dengan nilainya.
  • ⊃,/: lalu gabungkan string yang dihasilkan.
marinus
sumber
Itu selalu menyenangkan untuk melihat bahasa esoteris yang terlihat seperti omong kosong. ;)
nyuszika7h
2
@ nyuszika7h: Ini sebenarnya bahasa yang serius. Ini berasal dari tahun 1960-an dan masih digunakan. Itu akan terlihat sedikit kurang seperti omong kosong jika tidak golf.
marinus
Begitu, menarik.
nyuszika7h
@ nyuszika7h: Ya, secara teknis itu bahasa pemrograman yang berorientasi pada daftar, jadi Anda bisa mengatakan itu dirancang untuk golf kode, terutama mengingat itu menggunakan set karakter khusus yang dimaksudkan untuk membuat program lebih mudah dibaca, dan lebih sedikit bertele-tele. Dan itu adalah inspirasi untuk bahasa pemrograman J dan GolfScript.
Konrad Borowski
@xfix Saya pikir LISP adalah bahasa pemrograman berorientasi daftar? Kami menggunakan APL di universitas untuk pekerjaan nyata - bisa menangani array secara native sangat berguna. J dirancang oleh salah satu penemu APL sebagai "penggantinya" - tentu saja itu tidak berarti bahwa itu tidak berguna untuk kode golf ...
Jerry Jeremiah
2

Ruby: 102 karakter

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

Contoh dijalankan:

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

Penentu format tidak valid disimpan. Penentu format tanpa nilai argumen diganti dengan nilai kosong dari tipe yang diberikan.

manatwork
sumber
Anda dapat menyediakan fungsi anonim, jadi letakkan f
kucing
Memang. Tetapi seingat saya, pada saat memposting ini, fungsi anonim tidak diterima dengan suara bulat. Sedangkan untuk saat ini, jawaban Lua tidak diperbarui ke fungsi anonim (untuk menyimpan jumlah karakter yang sama), saya pikir saya tidak akan memulai kampanye pembaruan.
manatwork
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
Egor Skriptunoff
sumber
Bagus Versi Lua yang mana? 5.1.5 memberikan "angka cacat di dekat '1return'". Masalah kecil dengan "% c", gagal pada 'N' bukannya 78. Atau apakah itu juga hanya keanehan Lua lama saya?
manatwork
@manatwork - Coba di sini
Egor Skriptunoff
Yapp, bekerja di sana.
manatwork
Bekerja untuk saya di Lua 5.2.3.
nyuszika7h
1

C ++ (281 karakter)

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

Saya benci C ++, tapi sepertinya pilihan yang baik (saya benar-benar akan pergi dengan C, jika tidak char*pointer itu memerlukan terlalu banyak usaha untuk benar-benar berguna). Membawa char*argumen, dan std::stringhasil, tapi hei, itu C ++, jadi siapa yang peduli tentang konsistensi (dalam bahasa itu sendiri tidak konsisten)?

Konrad Borowski
sumber
Ini tidak dikompilasi, karena tidak memiliki fungsi utama.
nyuszika7h
@ nyuszika7h: Pertanyaannya adalah tentang membuat fungsi, bukan main. Tetapi jika Anda memerlukan sampel main, coba gist.github.com/xfix/8238576 (Saya menggunakan yang itu saat menguji fungsi ini).
Konrad Borowski
Benar, Anda tidak dapat benar-benar membuat mainfungsi yang bermakna , menambahkan satu hanya akan meningkatkan jumlah karakter. Jika saya tidak ingin mengubah kode, saya bisa menambahkan file header yang menyertainya dan #includedari program pengujian saya.
nyuszika7h
1

Java , 201 186 174 byte

12 byte terima kasih kepada 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;}

Cobalah online!

Biarawati Bocor
sumber
Saya tidak sepenuhnya yakin, tetapi saya pikir Anda dapat menghapus =s.charAt(0)dari char c=s.charAt(0). Itu masih berfungsi di TIO ketika saya melakukannya.
Kevin Cruijssen
@KevinCruijssen Saya bersumpah itu cukup pintar.
Leaky Nun
Saya tahu ini sudah lama, tetapi Anda dapat menyimpan 8 byte lebih banyak dengan mencetak langsung: 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 (dan beberapa lagi dengan mengkonversi ke Java 8, tetapi itu tidak benar-benar hal Anda, bukan?)
Kevin Cruijssen