formatowanie ciągów w stylu printf

9

Wyzwanie

Napisz funkcję, która implementuje printfformatowanie ciągów w stylu C.

Zasady

  1. Państwo musi wdrożyć przynajmniej %%, %c, %s, %di %f.
  2. Nie wolno używać wbudowanej metody formatowania ciągów.
  3. Nie wolno uruchamiać programów zewnętrznych ani łączyć się z Internetem z poziomu programu.
  4. Ty decydujesz, jak obsłużyć nieprawidłowe dane, ale Twój program nie może zakończyć się nienormalnie.
  5. Jeśli to możliwe, powinieneś napisać funkcję wariadyczną .

Słowa kluczowe „MUSZĄ”, „MUSI NIE”, „WYMAGANE”, „MUSZĄ”, „NIE MUSZĄ”, „POWINNY”, „NIE POWINNY”, „ZALECANE”, „MAJĄ” i „OPCJONALNIE” w tym dokumencie to należy interpretować zgodnie z opisem w RFC 2119 .

nyuszika7h
źródło
Co ma %czrobić? Całkiem pewny %s, %di %fsą na smyczki, wskazówki i pływaków respectivelly, ale pewien %c.
Sumurai8
%cwyświetla wartość ASCII przekazanego int IIRC
marinus
Drukuje znak, więc 97i 'a'oba staną asię na wyjściu.
nyuszika7h
nie musisz obsługiwać takich formularzy jak %-02dprawda? tylko trzy% c,% s,% d?
TY
@YOU Prawidłowo. Wystarczy.
nyuszika7h

Odpowiedzi:

4

APL (73)

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

Niektóre testy:

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

Wyjaśnienie:

  • G←'%!',⍺: przedrostek fikcyjnego specyfikatora do łańcucha (dla łatwiejszego przetwarzania)
  • (Z←G='%')/⍳⍴G: znajdź indeksy wszystkich %znaków w ciągu; przechowuj także maskę bitów wZ
  • ⌷∘G¨1↓1+: wybierz wszystkie znaki obok %s i upuść manekina.
  • ⍵,⍪: dopasuj każdy specyfikator do wartości z odpowiedniego argumentu.
  • {... }/: uruchom następującą funkcję dla każdej pary:
    • 'c'0≡⍵,∊⊃⍺: jeśli argument jest liczbą, a specyfikatorem jest c:
    • :⎕UCS⍺: następnie zwróć wartość Unicode argumentu,
    • ⋄⍕⍺: w przeciwnym razie zwraca ciąg reprezentujący argument.
  • : załącz
  • ⊂2∘↓¨Z⊂G: podziel ciąg znaków na %s, a następnie usuń pierwsze dwa znaki z każdego podłańcucha (tutaj przychodzi manekin) i dołącz wynik tego.
  • : utwórz matrycę z dwóch zamkniętych tablic, dopasowując każdy podciąg do wartości, która powinna za nim podążać.
  • ,⌿: połącz każdy podciąg z jego wartością.
  • ⊃,/: następnie dołącz wynikowe ciągi.
marinus
źródło
Zawsze fajnie jest oglądać ezoteryczne języki, które wyglądają jak bełkot. ;)
nyuszika7h
2
@ nyuszika7h: To właściwie poważny język. Pochodzi z lat 60. XX wieku i wciąż jest w użyciu. Gdyby nie grał w golfa, wyglądałby trochę mniej jak bełkot.
marinus
Rozumiem, interesujące.
nyuszika7h
@ nyuszika7h: Cóż, technicznie jest to język programowania zorientowany na listy, więc można powiedzieć, że jest przeznaczony do golfa kodowego, szczególnie biorąc pod uwagę, że używa specjalnego zestawu znaków, który ma uczynić programy bardziej czytelnymi i mniej gadatliwymi. To była inspiracja dla języka programowania J i GolfScript.
Konrad Borowski
@xfix Myślałem, że LISP jest językiem programowania zorientowanym na listy? Używaliśmy APL na uniwersytecie do prawdziwej pracy - możliwość natywnego obsługiwania tablic jest naprawdę przydatna. J został zaprojektowany przez jednego z wynalazców APL jako jego „następca” - oczywiście nie oznacza to, że nie jest przydatny do golfa kodowego ...
Jerry Jeremiah
2

Rubin: 102 znaki

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

Przykładowy przebieg:

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

Niepoprawne specyfikatory formatu są przechowywane na miejscu. Specyfikatory formatu bez wartości argumentu są zastępowane pustą wartością danego typu.

człowiek w pracy
źródło
Możesz podać anonimową funkcję, więc upuść wiodącegof
kota
W rzeczy samej. Ale, jak pamiętam, w chwili opublikowania tego anonimowe funkcje nie zostały jednogłośnie przyjęte. Jak na razie ani odpowiedź Lua nie została zaktualizowana do funkcji anonimowej (aby zapisać taką samą liczbę znaków), myślę, że nie rozpocznę kampanii aktualizacji.
manatwork
2

Lua 5.2, 115 bajtów

-- 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
źródło
Niezłe. Która wersja Lua? 5.1.5 podaje „zniekształcony numer przy„ 1 zwrocie ””. Mały problem z „% c”, kończy się niepowodzeniem na „N” zamiast 78. A może to tylko osobliwość mojej starej Lui?
manatwork
@manatwork - Spróbuj tutaj
Egor Skriptunoff
Tak, tam działa.
manatwork
Działa dla mnie na Lua 5.2.3.
nyuszika7h
1

C ++ (281 znaków)

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

Nienawidzę C ++, ale wydawało mi się, że to dobry wybór (naprawdę wybrałbym C, jeśli nie, ten char*wskaźnik wymaga zbyt wiele wysiłku, aby był naprawdę użyteczny). Bierze char*argumenty i std::stringwynik, ale hej, to jest C ++, więc kogo obchodzi spójność (w języku, który sam nie jest spójny)?

Konrad Borowski
źródło
Nie kompiluje się, ponieważ nie ma głównej funkcji.
nyuszika7h
@ nyuszika7h: Pytanie dotyczyło wykonania funkcji, a nie main. Ale jeśli potrzebujesz próbki main, spróbuj gist.github.com/xfix/8238576 (użyłem tego podczas testowania tej funkcji).
Konrad Borowski
To prawda, że ​​tak naprawdę nie można wykonać sensownej mainfunkcji, dodanie jednej zwiększy liczbę znaków. Gdybym nie chciał modyfikować kodu, mógłbym dodać towarzyszący mu plik nagłówkowy i #includemój program testowy.
nyuszika7h
1

Java , 201 186 174 bajtów

12 bajtów dzięki 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;}

Wypróbuj online!

Leaky Nun
źródło
Nie jestem do końca pewien, ale myślę, że można usunąć =s.charAt(0)z char c=s.charAt(0). Nadal działa w TIO, kiedy to robię.
Kevin Cruijssen
@KevinCruijssen Przysięgam, że to całkiem sprytne.
Leaky Nun
Wiem, że minęło trochę czasu, ale możesz zaoszczędzić 8 dodatkowych bajtów, drukując bezpośrednio: 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 bajtów (i trochę więcej, przechodząc na Javę 8, ale to nie jest twoja sprawa, prawda?)
Kevin Cruijssen