Подтвердить что ты не робот

Как работает этот однострочный Perl?

Итак, я заметил, что last.fm нанимает в моей области, и так как я знаю несколько человек которые работали там, хотя я и применяю.

Но я подумал, что лучше сначала взглянуть на текущий штат.

У всех на этой странице есть симпатичный/умный/немой strapline, например: "Является ли жизнь не тысячей раз слишком короткой для нас, чтобы вылечить себя?". На самом деле это было довольно забавно, пока я не добрался до этого:

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'

Который я не мог удержаться от вставки в мой терминал (вроде бы, глупость, может быть), но он напечатал:

Еще один хаккер Last.fm,

Я подумал, что было бы относительно легко понять, как работает однострочный Perl. Но я не мог понять документацию, и я не знаю Perl, поэтому я даже не был уверен, что читаю соответствующую документацию.

Итак, я попытался изменить цифры, которые ни к чему не привели. Поэтому я решил, что это действительно интересно и стоит выяснить.

Итак, "как это работает" немного расплывчато, мой вопрос в основном,

Что это за числа? Почему существуют отрицательные числа и положительные числа, и имеет ли смысл отрицательность или положительность?

Что делает комбинация операторов +=$_?

Что pack+q,c*,, делать?

4b9b3361

Ответ 1

Это вариант на "Просто еще один хакер Perl" , Perl meme. Как JAPHs идут, это одно относительно ручное.

Первое, что вам нужно сделать, это выяснить, как разбирать программу perl. В нем отсутствуют круглые скобки вокруг вызовов функций и интересными способами используются операторы + и quote-like. Исходная программа такова:

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 является функцией, тогда как print и map являются операторами списка. В любом случае, имя функции или не нулевого оператора, за которым следует знак плюс, не может использовать + в качестве двоичного оператора, поэтому оба знака + в начале унарные операторы. Эта странность описана в руководстве .

Если мы добавим круглые скобки, используйте синтаксис блока для map и добавьте немного пробелов, получим:

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

Следующий сложный бит - это q здесь q котировочный оператор. Это чаще всего записывается с одинарными кавычками:

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

Помните, что унарный плюс - это не-op (кроме форсирования скалярного контекста), поэтому теперь все должно выглядеть более знакомым. Это вызов функции pack с форматом c*, что означает "любое количество символов, указанное их номером в текущем наборе символов", Альтернативный способ написать это

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

Функция map применяет поставляемый блок к элементам списка аргументов по порядку. Для каждого элемента $_ устанавливается значение элемента, а результат вызова map - это список значений, возвращаемых при выполнении блока на последующих элементах. Более длинный способ написать эту программу будет

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

Переменная $. содержит общее количество чисел. Цифры выбраны так, что общее количество - это коды ASCII символов, которые автор хочет напечатать: 74 = J, 74 + 43 = 117 = u, 74 + 43-2 = 115 = s, и т.д. Они отрицательные или положительные в зависимости от того, каждый ли символ до или после предыдущего в порядке ASCII.

Для вашей следующей задачи объясните этот JAPH (созданный EyesDrop).

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

Не используйте это в производственном коде.

Ответ 2

Основная идея этого довольно проста. У вас есть массив, содержащий значения ASCII символов. Чтобы сделать вещи немного сложнее, вы не используете абсолютные значения, а относительные, кроме первого. Поэтому идея состоит в том, чтобы добавить конкретное значение к предыдущему, например:

  • 74 → J
  • 74 + 43 → u
  • 74 + 42 + (-2) → s

Несмотря на то, что $. является специальной переменной в Perl, в данном случае это не означает ничего особенного. Он просто используется для сохранения предыдущего значения и добавления текущего элемента:

map($.+=$_, ARRAY)

В основном это означает добавление текущего элемента списка ($_) к переменной $.. Это вернет новый массив с правильными значениями ASCII для нового предложения.

Функция q в Perl используется для одиночных кавычек, буквенных строк. Например. вы можете использовать что-то вроде

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

Это означает, что pack+q,c*,, в основном pack 'c*', ARRAY. Модификатор c* в pack интерпретирует значение как символы. Например, он будет использовать значение и интерпретировать его как символ.

В основном это сводится к следующему:

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