2012-06-01 14 views
20

Quindi, mi è capitato di notare che last.fm sta assumendo nella mia zona, e dal momento che ho conosciuto alcune persone who workedthere, ho pensato di applicare.In che modo funziona davvero questo one-liner Perl?

Ma ho pensato che sarebbe meglio dare un'occhiata al current staff prima.

Tutti in quella pagina hanno una linea di cintura carina/intelligente/stupida, come "La vita non è mille volte troppo breve per noi per annoiare noi stessi?". In realtà, è stato molto divertente, fino a quando ho avuto modo di questo:

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' 

Il che non ho potuto resistere incollare nel mio terminale (genere di una cosa stupida da fare, forse), ma stampato:

Solo un altro hacker, Last.fm,

ho pensato che sarebbe stato relativamente facile da capire come questo Perl funziona uno-liner. Ma non ho potuto davvero dare un senso alla documentazione, e non conosco Perl, quindi non ero nemmeno sicuro di leggere la documentazione pertinente.

Così ho provato a modificare i numeri, che non mi ha portato da nessuna parte. Quindi ho deciso che era davvero interessante e vale la pena capirlo.

Quindi, 'come funziona' essere un po 'vago, la mia domanda è soprattutto,

Quali sono quei numeri? Perché ci sono numeri negativi e numeri positivi, e la negatività o positività contano?

Cosa fa la combinazione di operatori +=$_?

Cosa fa pack+q,c*,,?

+0

Il mio attuale: '(* STORE, * TIESCALAR) = map {eval" sub {$ _} "} qw'map {stampa && sleep $ |} split //, pop bless \ $ | ++ '; tie $ t, main; $ t = "Solo un altro hacker Perl, \ n" –

risposta

28

Questa è una variante “Just another Perl hacker”, un meme Perl. Come JAPHs, questo è relativamente docile.

La prima cosa che devi fare è capire come analizzare il programma perl. Manca di parentesi attorno alle chiamate di funzione e utilizza gli operatori + e preventivo in modi interessanti. Il programma originale è questo:

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 è una funzione, mentre print e map sono list operators. In entrambi i casi, una funzione o un nome operatore non nullo immediatamente seguito da un segno più non può utilizzare + come operatore binario, quindi entrambi i segni + all'inizio sono unary operators. Questa stranezza è descritta nello manual.

Se aggiungiamo parentesi, utilizzare la sintassi del blocco per map, e aggiungere un po 'di spazio bianco, otteniamo:

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))) 

La prossima po' complicato è che q Ecco l'qquote-like operator. E 'più comunemente scritto con apici:

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))) 

ricordare che il più unario è un no-op (a parte forzando un contesto scalare), quindi le cose dovrebbero ora essere alla ricerca più familiare. Questa è una chiamata alla funzione pack, con un formato di c*, che significa "qualsiasi numero di caratteri, specificato dal loro numero nel set di caratteri corrente". Un modo alternativo per scrivere questo è

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

La funzione map applica il blocco alimentata agli elementi della lista degli argomenti in ordine. Per ogni elemento, $_ è impostato sul valore dell'elemento e il risultato della chiamata map è l'elenco di valori restituiti eseguendo il blocco sugli elementi successivi. Un modo più tempo per scrivere questo programma sarebbe

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

La variabile $. contiene un totale parziale dei numeri. I numeri vengono scelti in modo che il totale parziale sia i codici ASCII dei caratteri che l'autore desidera stampare: 74 = J, 74 + 43 = 117 = u, 74 + 43-2 = 115 = s, ecc. Sono negativi o positivo a seconda che ciascun carattere sia precedente o successivo a quello precedente in ordine ASCII.

Per il tuo prossimo compito, spiega questo JAPH (prodotto da EyesDrop).

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

Non utilizzare nulla di questo nel codice di produzione.

+1

tutto ciò che riguarda questa risposta è fantastico.Ottima spiegazione, hai aggiunto un po 'di link, hai aggiunto un follow-up - vorrei poter +20 questo –

22

L'idea alla base di questo è abbastanza semplice. Hai una matrice contenente i valori ASCII dei personaggi. Per rendere le cose un po 'più complicate non si usano i valori assoluti, ma quelli relativi tranne il primo. Così l'idea è quella di aggiungere il valore specifico a quello precedente, per esempio:

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

Anche se $. è una variabile speciale in Perl, non significa nulla di speciale in questo caso. E 'solo utilizzato per salvare il valore precedente e aggiungere l'elemento corrente:

map($.+=$_, ARRAY) 

Fondamentalmente significa aggiungere l'elemento della lista corrente ($_) alla variabile $.. Ciò restituirà un nuovo array con i valori ASCII corretti per la nuova frase.

La funzione q in Perl viene utilizzata per stringhe letterali con quotatura singola. Per esempio. si può usare qualcosa come

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

Ciò significa che pack+q,c*,, è fondamentalmente pack 'c*', ARRAY.Il modificatore c* in pack interpreta il valore come caratteri. Ad esempio, utilizzerà il valore e lo interpreterà come un personaggio.

si riduce sostanzialmente a questo:

#!/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); 
Problemi correlati