TMTOWTDI
Это самый важный совет по игре в гольф на Perl, который вам нужно знать. Всякий раз, когда вы смотрите на какую-то слишком длинную последовательность символов, которая вам абсолютно необходима для выполнения вашей задачи, спросите себя, нет ли другого способа получить тот же эффект с помощью другой функции. Там обычно есть. Вот только несколько:
~~
обеспечивает скалярный контекст и на 4 символа короче, чем scalar
.
y///c
на один символ короче, чем length
при получении длины $_
.
Нужно перебрать символы $_
? Заменить split//
на /./gs
. (Или используйте, /./g
если вы также хотите пропустить переводы строки.) Это работает с другими переменными: замените split//,$x
на $x=~/./gs
.
Каждый встроенный Perl возвращает что-то. print
возвращает 1, например, чтобы указать успешный ввод / вывод. Если вам нужно инициализировать $_
к истинному значению, например, $_=print$foo
позволяет убить двух зайцев одним выстрелом.
Почти каждое утверждение в Perl может быть написано как выражение, что позволяет использовать его в более широком контексте. Несколько операторов могут стать множественными выражениями, соединенными запятыми. Тесты могут быть выполнены с операторами короткого замыкания ?:
&&
||
, а также с and
и or
, которые делают то же самое, но с приоритетом ниже, чем у всех других операторов (включая присвоение). Циклы могут быть сделаны через map
или grep
. Даже такие слова как next
, last
и return
может быть использовано в контексте выражения, даже если они не возвращаются! Помня об этих видах преобразований, вы сможете заменить блоки кода выражениями, которые можно встроить в более широкий контекст.
$_=print""
короче$_=print$foo
.$foo
. В противном случае,$_=1
намного короче$_=print""
и имеет тот же эффект.$x
? В противном случае вы могли бы просто сделать/./gs
и/./g
.Злоупотребляйте специальными переменными Perl!
Как было отмечено в предыдущем ответе
$/
и$"
инициализируются по умолчанию"\n"
и" "
, соответственно.$,
и$\
оба установленыundef
по умолчанию, и на 3 символа короче.Установка
$\
значения приведет к его добавлению к каждомуprint
. Например:perl -ple '$\="=".hex.$/'
это удобный шестнадцатеричный преобразователь.Если вы не читаете файлы из командной строки, вы можете использовать
-i
переключатель командной строки в качестве дополнительного канала для ввода строки. Его значение будет сохранено в$^I
.$=
заставляет все, что ему назначено, быть целым числом. Попробуйте запуститьperl -ple '$_=$==$_'
и дать ему различные inupts. Аналогично,$-
заставляет его значение быть неотрицательным целым числом (т. Е. Начальный тире обрабатывается как не числовой символ).Вы можете использовать
$.
в качестве логического флага, который автоматически сбрасывается в истинное (ненулевое) значение на каждой итерацииwhile(<>)
цикла.источник
-n
и непревзойденные фигурные скобкиХорошо известно, что ключ командной строки
-n
можно использовать для выполнения скрипта один раз для каждой строки.perl --help
говорит:Что он не говорит явно, так это то, что Perl не просто предполагает цикл вокруг программы; это буквально оборачивается
while (<>) { ... }
вокруг этого.Таким образом, следующие команды эквивалентны друг другу:
-p
и непревзойденные фигурные скобкиКак и выше,
-p
коммутатор оборачиваетсяwhile (<>) { ... ; print }
вокруг программы.При использовании несоответствующих фигурных скобок,
perl -p 'code}{morecode'
печать будет выполняться только один раз после выполненияcode
для всех строк ввода, после чего следуетmorecode
.Поскольку
$_
приmorecode;print
выполнении не определено, разделитель выходной записи$\
может использоваться для печати фактического вывода.Например
читает одно число в строке из STDIN и печатает их сумму.
источник
#!perl -n
первой строки, верно?-p
и$\
) в одном из ответов @primo на Perl. Читать его ответы - хороший совет Perl сам по себе.}for(...){
между скобками также очень удобно, например, codegolf.stackexchange.com/a/25632Используйте
$_
для устранения скалярных ссылок. Это специальная переменная, которая используется по умолчанию большинством функций, и просто не указывать параметры - это ярлык для ссылки на эту переменную.Изменяя
$n
на$_
, вы можете изменить$n=<>;chop$n;print$n
на$_=<>;chop;print
Здесь
print
функция печатает содержимое$_
по умолчанию, аchop
также работает$_
.источник
$_=<>;
требуется, не<>;
читать строки в$_
автоматически?$_=<>;print
и<>;print
. Первый повторяет мне то, что я печатаю, а другой нет.print while(<>)
. Не уверен, что это особый случай или за ним стоит какая-то логическая логика, но ни<>
часть,perlop
ниwhile
часть,perlsyn
похоже, не упоминают об этом поведении.while(<>)
- это особый случай, задокументированный в perlsyn, Операторы ввода / вывода: «Если и только если входной символ является единственной вещью внутри условного выражения while (даже если замаскировано под« for (;;) » цикл), значение автоматически присваивается глобальной переменной $ _, уничтожая все, что было ранее. "Всегда используйте специальные переменные Perl, например:
$"
вместо" "
$/
вместо"\n"
Они имеют дополнительное преимущество, заключающееся в том, что они являются гарантированным длинно-символьным идентификатором с помощью лексера. Это позволяет связать его с последующим ключевым словом, например:
print$.for@_
Список всех специальных переменных доступен здесь: Специальные переменные
источник
Не используйте
qw
. Это пустая трата двух символов, которые можно было бы использовать лучше. Например, не пишите следующее.Вместо этого используйте голые слова.
Или, если вы не можете использовать голые слова, используйте
glob
синтаксис.glob
синтаксис также может быть использован для интересных эффектов.источник
Используйте модификаторы операторов вместо составных операторов.
Сложные операторы, как правило, требуют скобок для аргумента и фигурных скобок для блока, тогда как модификаторы операторов не нуждаются ни в одном.
Для сравнения:
$a++,$b++while$n--
противwhile($n--){$a++;$b++}
chop$,if$c
противif($c){chop$,}
Обратите внимание, что последний пример связан с
$c&&chop$,
, но начинает действительно сиять для большинства операций с несколькими операторами. В основном все, что теряет приоритет оператора&&
.источник
Не
use strict
. (не цитируйте меня по этому поводу, контекст PCG.SE как бы имеет значение) И, что более важно, не кодируйте, как если бы он был строгим. Обычные подозреваемые:my
указывайте переменные, если вы можете избежать этого. Единственные переменные, которые действительно нужныmy
- это те, которые вы хотите получить в лексическом смысле. Это почти ни один из них при игре в гольф, где вам не нужна защита прицела и вы, как правило, полностью контролируете рекурсию.источник
print hello
не сработает Это на самом деле означаетprint hello $_
(печать$_
в файл дескрипторhello
).print
, и теперь я не могу найти хороший и короткий пример)Я уверен, что у некоторых из них есть формальные имена, и я просто не знаю их.
print $n++ while ($n < 10)
$var = join('',<>)
print ('X'*10) . "\n";
дольше, чемprint ('X'*10) . $/;
say
Функция Perl корочеprint
, но вам придется запускать код-E
вместо-e
a..z
или дажеaa..zz
. Если нужно в качестве строки, используйтеjoin
.$z = 'z'; print ++$z;
будет отображатьсяaa
Это все, что я могу думать прямо сейчас. Я могу добавить еще немного позже.
источник
print ('X'*10) . $/;
должен делать? Для меня это печатает0
и без перевода строки. С одной стороны, круглые скобки становятся аргументом вызова в стиле функцииprint
, который связывается более жестко, чем.
. И ты имел в видуx
вместо*
или что-то?while
,join'',<>;
также работает без них.Используйте несловесные символы в качестве имен переменных
Использование
$%
вместо$a
может позволить вам поместить имя переменной рядом сif
,for
илиwhile
построить как в:@r=(1,2,3,4,5);$%=4;
print$_*$%for@r
Многие из них можно использовать, но проверьте документы и ответ @ BreadBox, для которых есть магические эффекты!
Используйте карту, когда вы не можете использовать модификаторы операторов
Если вы не можете использовать модификаторы операторов согласно ответу @ JB , карта может сохранить байт:
for(@c){}
противmap{}@c;
и полезно, если вы хотите делать вложенные итерации, поскольку вы можете поместить
for
циклы postfix внутриmap
.Используйте все магические переменные регулярного выражения
В Perl есть магические переменные для «текст до совпадения» и «текст после совпадения», поэтому можно разбить на группы по два с потенциально меньшим количеством символов:
Это также может хорошо подойти для замены
substr
:Если вам нужно содержимое матча,
$&
можно использовать, например:Замените сабы с длинными именами на более короткие
Если
print
в вашем коде вы говорите «скажем» четыре или более раз (это, очевидно, зависит от длины вызываемой вами подпрограммы), замените ее на более короткое имя:против
Заменить условные инкременты / декременты
Если у вас есть такой код:
вы можете использовать:
вместо этого, чтобы сохранить несколько байтов.
Преобразовать в целое число
Если вы не присваиваете переменную и не можете использовать подсказку хлебной корзины , вы можете использовать выражение
0|
:Однако стоит отметить, что вам не нужно использовать целое число для доступа к индексу массива:
источник
redo
добавляет поведение цикла в блок безfor
илиwhile
.{redo}
это бесконечный цикл.источник
Не заключайте в скобки вызовы функций.
Perl позволяет вам вызывать известную (базовую или предварительно объявленную) функцию с использованием
NAME LIST
синтаксиса. Это позволяет вам сбросить&
сигил (если вы все еще использовали его), а также скобки.Например:
$v=join'',<>
Полная документация
источник
Попробуйте использовать значение выражения присваивания, например так:
Это работает, потому что
$n
в Perl 2 символа. Вы можете изменить ,$n
чтобы()
без каких - либо затрат, и сохранить 1 точку с запятой, перемещая задания в скобках.источник
Вы можете запустить несколько различных операторов в рамках вложенной троичной логики.
Предположим , у вас есть большой
if
-elsif
заявление. Это может быть любая логика и любое количество утверждений.Вы можете использовать
(cmd1, cmd2, cmd3)
внутри троичного оператора для запуска всех команд.Вот фиктивный пример:
источник
Используйте
select(undef,undef,undef,$timeout)
вместоTime::HiRes
(Взято с https://stackoverflow.com/a/896928/4739548 )
Многие проблемы требуют от вас спать с большей точностью, чем целые числа.
select()
аргумент тайм-аут может сделать именно это.гораздо эффективнее, чем:
Первый занимает всего 20 байтов, тогда как последний занимает 39. Однако первый требует, чтобы вы не использовали его
$u
и никогда не определяли.Если вы собираетесь использовать его, импорт
Time::HiRes
окупается, но если вам это нужно только один раз, использованиеselect($u,$u,$u,0.1)
экономит 19 байт, что, безусловно, является улучшением в большинстве случаев.источник
Сократите свои печатные заявления
Если в задании не указано иное, вам не нужны завершающие символы новой строки.
Наш «вызов» говорит «вывести случайное число от 0 до 9 для STDOUT». Мы можем взять этот код (28 байт):
И сократить его до этого (25 байт):
просто печатая переменную. Этот последний относится только к этой проблеме конкретно (19 байт):
но это работает только тогда, когда вам не нужно ничего делать с переменной между присваиванием и печатью.
источник
Используйте глобусы как строковые литералы
Изредка (часто при работе с квайнами или проблемами с ограниченными источниками ) вы получаете большую выгоду от способности вкладывать строковые литералы. Обычно, вы бы сделали это с
q(…)
. Однако, в зависимости от того, какие символы вам нужны внутри строки, вы можете сохранить байт и использовать<…>
оператор glob. (Обратите внимание, что то, что находится внутри угловых скобок, не может выглядеть как дескриптор файла, и не может выглядеть так, как будто оно предназначено для расширения в список имен файлов, что означает, что довольно много символов не будут работать правильно.)источник
Используйте выражение регулярное выражение.
Достойной иллюстрацией этого является следующий код, формирующий вход в синусоидальную волну:
Как видите, это довольно компактный способ перебора символов в стандартном вводе. Вы можете использовать другое регулярное выражение, чтобы изменить способ сопоставления вещей.
источник