2012-06-01 10 views
20

Tak więc, zdarzyło mi się zauważyć, że last.fm zatrudnia w mojej okolicy, a ponieważ znam kilka osób, to who workedthere, chociaż staram się o to.Jak działa ten pojedynczy liniowiec Perla?

Ale pomyślałem, że najpierw lepiej przyjrzeć się current staff.

Wszyscy na tej stronie mają ładny/sprytny/głupi pasek, np. "Czy życie nie jest tysiąc razy za krótkie, abyśmy mogli się zanudzić?". W rzeczywistości, to było dość zabawne, dopóki nie dostał się do tego:

perl -e'print+pack+q,c*,,map$.+=$_,74,43,-2,1,-84, 65,13,1,5,-12,-3, 13,-82,44,21, 18,1,-70,56, 7,-77,72,-7,2, 8,-6,13,-70,-34' 

której nie mógł się oprzeć wklejając do mojego terminala (niby głupie, być może), ale drukowane:

kolejny haker Last.fm,

Myślałem, że byłoby stosunkowo łatwo zorientować się, w jaki sposób działa jeden Perl-liner. Ale naprawdę nie mogłem zrozumieć dokumentacji i nie znam Perla, więc nie byłem nawet pewien, czy czytałem odpowiednią dokumentację.

Próbowałem więc zmodyfikować numery, które doprowadziły mnie do nikąd. Postanowiłem więc, że jest naprawdę interesująca i warta wymyślenia.

Tak, „jak to działa” jest nieco niejasne, moje pytanie jest głównie

Jakie są te numery? Dlaczego istnieją liczby ujemne i liczby pozytywne, a czy negatywność lub pozytywność ma znaczenie?

Co robi kombinacja operatorów +=$_?

Co robi pack+q,c*,,?

+0

Moja aktualna: '(* SKLEP * TIESCALAR) = map {eval "sub {$ _}"} {print qw'map && sen $ |} // Podział, pop błogosławię \ $ | ++"; tie $ t, main; $ t = "Tylko kolejny haker Perla, \ n" ' –

Odpowiedz

28

Jest to wariant “Just another Perl hacker”, memu Perl. Podobnie jak JAPH, ten jest stosunkowo łagodny.

Pierwszą rzeczą, którą musisz zrobić, to dowiedzieć się, jak analizować program Perl. Brakuje nawiasów wokół wywołań funkcji i używa w ciekawy sposób operatorów + i cytatów. Oryginalny program jest taki:

print+pack+q,c*,,map$.+=$_,74,43,-2,1,-84, 65,13,1,5,-12,-3, 13,-82,44,21, 18,1,-70,56, 7,-77,72,-7,2, 8,-6,13,-70,-34 

pack jest funkcją, natomiast print i maplist operators. Tak czy inaczej, funkcja lub non-sygnalnych nazwę operatora bezpośrednio za znakiem plus nie może być za pomocą + jako operator binarny, więc oba + znaki na początku są unary operators. Ta osobliwość jest opisana w manual.

Jeśli dodamy nawiasy, użyj składni blokowy dla map i dodać trochę spacji, otrzymujemy:

print(+pack(+q,c*,, 
      map{$.+=$_} (74,43,-2,1,-84, 65,13,1,5,-12,-3, 13,-82,44,21, 
         18,1,-70,56, 7,-77,72,-7,2, 8,-6,13,-70,-34))) 

Następny nieco kłopotliwe jest to, że q oto qquote-like operator. Jest powszechnie napisany z apostrofami:

print(+pack(+'c*', 
      map{$.+=$_} (74,43,-2,1,-84, 65,13,1,5,-12,-3, 13,-82,44,21, 
         18,1,-70,56, 7,-77,72,-7,2, 8,-6,13,-70,-34))) 

Pamiętaj, że jednoskładnikowa plusem jest no-op (oprócz zmuszając kontekst skalarny), więc wszystko powinno być teraz patrząc bardziej zaznajomieni. Jest to wywołanie funkcji pack o formacie c*, co oznacza "dowolną liczbę znaków określoną przez ich liczbę w bieżącym zestawie znaków". Alternatywny sposób napisać to

print(join("", map {chr($.+=$_)} (74, …, -34))) 

Funkcja map zastosowanie dostarczonego bloku do elementów listy argumentów w kolejności. Dla każdego elementu, $_ jest ustawiony na wartość elementu, a wynik rozmowy map lista wartości zwracanych przez wykonanie bloku na kolejnych elementów. Dłuższy sposób napisać ten program byłby

@list_accumulator =(); 
for $n in (74, …, -34) { 
    $. += $n; 
    push @list_accumulator, chr($.) 
} 
print(join("", @list_accumulator)) 

Zmienna $. zawiera działa łącznie z numerami. Liczby są tak dobrane, że bieżąca suma jest kody ASCII znaków autor chce wydrukować: 74 = J, 74 + 43 = 117 = u, 74 + 43-2 = 115 = s, itd. Oni są negatywne lub dodatni w zależności od tego, czy każdy znak jest przed, czy po poprzednim w kolejności ASCII.

Do następnego zadania, wyjaśnić tę JAPH (produkowany przez EyesDrop).

''=~('(?{'.('-)@.)@_*([]@[email protected]/)(@)@[email protected]),@(@@[email protected])' 
^'][)@]`}`]()`@[email protected]]@%[`}%[@`@!#@%[').',"})') 

Nie wolno używać tego w kodzie produkcyjnym.

+1

wszystko na temat tej odpowiedzi jest niesamowite.Świetne wyjaśnienie, dodałeś kilka linków, dodałeś kontynuację - chciałbym móc to zrobić +20 –

22

Podstawowy pomysł jest dość prosty. Masz tablicę zawierającą wartości ASCII znaków. Aby nieco bardziej skomplikować, nie używaj wartości bezwzględnych, ale względnych, z wyjątkiem pierwszego. Więc chodzi o to, aby dodać konkretną wartość do poprzedniego, na przykład:

  1. 74 ->J
  2. 74 + 43 ->u
  3. 74 + 42 + (-2) ->s

Mimo że $. jest specjalną zmienną w Perlu, nie oznacza to nic specjalnego w tym przypadku. To jest po prostu wykorzystywane do zapisywania poprzednią wartość i dodać bieżący element:

map($.+=$_, ARRAY) 

zasadzie oznacza to dodać bieżący element listy ($_) do zmiennej $.. Spowoduje to zwrócenie nowej tablicy z poprawnymi wartościami ASCII dla nowego zdania.

Funkcja q w języku Perl jest używana dla pojedynczych cudzysłowów, literałów. Na przykład. można użyć coś podobnego

q/Literal $1 String/ 
q!Another literal String! 
q,Third literal string, 

Oznacza to, że pack+q,c*,, jest w zasadzie pack 'c*', ARRAY.Modyfikator c* w pack interpretuje wartość jako znaki. Na przykład użyje wartości i zinterpretuje ją jako znak.

To w zasadzie sprowadza się do tego:

#!/usr/bin/perl 
use strict; 
use warnings; 

my $prev_value = 0; 

my @relative = (74,43,-2,1,-84, 65,13,1,5,-12,-3, 13,-82,44,21, 18,1,-70,56, 7,-77,72,-7,2, 8,-6,13,-70,-34); 
my @absolute = map($prev_value += $_, @relative); 

print pack("c*", @absolute);