2012-06-01 20 views
20

Entonces, me di cuenta de que last.fm está contratando en mi área, y como conozco a algunas personas who workedthere, pensé en postularme.¿Cómo funciona este Perl de una sola línea?

Pero pensé que sería mejor echarle un vistazo al current staff primero.

Todos en esa página tienen una línea linda/inteligente/tonta, como "¿No es la vida mil veces demasiado corta para aburrirnos?". De hecho, fue bastante divertido, hasta que llegué a esto:

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' 

Lo cual no pudo resistirse a pegar en mi terminal (una especie de estupidez, tal vez), pero impreso:

Sólo otro hacker Last.fm,

pensé que sería relativamente fácil de averiguar cómo Perl obras de una sola línea. Pero realmente no podía entender la documentación, y no conozco a Perl, así que ni siquiera estaba seguro de estar leyendo la documentación relevante.

Así que traté de modificar los números, lo que no me llevó a ninguna parte. Así que decidí que era realmente interesante y que valía la pena descubrirlo.

Así, 'cómo funciona' ser un poco vago, mi pregunta es, principalmente,

¿Cuáles son esos números? ¿Por qué hay números negativos y números positivos? ¿Importa la negatividad o la positividad?

¿Qué hace la combinación de operadores +=$_?

¿Qué está haciendo pack+q,c*,,?

+0

Mi actual: '(* STORE, * TIESCALAR) = mapa {eval" sub {$ _} "} qw'map {print && sleep $ |} split //, pop bless \ $ | ++ '; tie $ t, main; $ t = "Simplemente otro hacker de Perl, \ n" ' –

Respuesta

28

Esta es una variante de “Just another Perl hacker”, un meme Perl. Como JAPH van, este es relativamente manso.

Lo primero que debe hacer es averiguar cómo analizar el programa perl. Carece de paréntesis alrededor de las llamadas a funciones y usa el + y operadores similares a comillas en formas interesantes. El programa original es la siguiente:

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 es una función, mientras que print y map son list operators. De cualquier manera, una función o nombre de operador no nulario seguido inmediatamente por un signo más no puede estar usando + como operador binario, por lo tanto, ambos signos + al comienzo son unary operators. Esta rareza se describe en el manual.

Si sumamos paréntesis, utilice la sintaxis del bloque de map, y añadir un poco de espacio en blanco, se obtiene:

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 siguiente parte difícil es que q aquí es el qquote-like operator. Está escrito con mayor frecuencia entre comillas simples:

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

Recuerde que el signo más unario es un no-op (aparte de forzar un contexto escalar), así que las cosas ahora deben buscar más familiar. Esta es una llamada a la función pack, con un formato de c*, que significa "cualquier número de caracteres, especificado por su número en el juego de caracteres actual". Una forma alternativa de escribir esto es

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

La función map aplica el bloque suministrada a los elementos de la lista de argumentos en orden. Para cada elemento, $_ se establece en el valor del elemento, y el resultado de la llamada map es la lista de valores devueltos al ejecutar el bloque en los elementos sucesivos. Una manera más tiempo para escribir este programa sería

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

La variable $. contiene un total acumulado de los números. Los números se eligen para que el total acumulado sea el código ASCII de los caracteres que el autor desea imprimir: 74 = J, 74 + 43 = 117 = u, 74 + 43-2 = 115 = s, etc. Son negativos o positivo dependiendo de si cada carácter es anterior o posterior al anterior en orden ASCII.

Para su próxima tarea, explique este JAPH (producido por EyesDrop).

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

No utilice nada de esto en el código de producción.

+1

todo acerca de esta respuesta es increíble.Gran explicación, agregaste un montón de enlaces, agregaste un seguimiento - desearía poder +20 –

22

La idea básica detrás de esto es bastante simple. Usted tiene una matriz que contiene los valores ASCII de los caracteres. Para hacer las cosas un poco más complicadas, no se usan valores absolutos, sino relativos, excepto el primero. Así que la idea es agregar el valor específico a la anterior, por ejemplo:

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

Aunque $. es una variable especial en Perl, no significa nada especial en este caso. Sólo se utiliza para guardar el valor anterior y agregar el elemento actual:

map($.+=$_, ARRAY) 

Básicamente esto significa añadir el elemento de lista actual ($_) a la variable $.. Esto devolverá una nueva matriz con los valores ASCII correctos para la nueva oración.

La función q en Perl se utiliza para cadenas literales de una sola cita. P.ej. se puede usar algo como

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

Esto significa que pack+q,c*,, es básicamente pack 'c*', ARRAY.El modificador c* en pack interpreta el valor como caracteres. Por ejemplo, usará el valor e interpretará como un personaje.

Básicamente se reduce a esto:

#!/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); 
Cuestiones relacionadas