TMTOWTDI
Essa é a dica de golfe Perl mais importante que você precisa conhecer. Sempre que você estiver olhando para uma sequência muito longa de caracteres que você absolutamente precisa ter para realizar sua tarefa, pergunte a si mesmo se não há outra maneira de obter o mesmo efeito usando um recurso diferente. Geralmente existe. Aqui estão apenas algumas:
~~
impõe um contexto escalar e é 4 caracteres menor que scalar
.
y///c
é um caractere mais curto do que length
quando obtém o comprimento de $_
.
Precisa iterar sobre os caracteres $_
? Substitua split//
por /./gs
. (Ou use /./g
se você também quiser pular novas linhas.) Isso funciona com outras variáveis: substitua split//,$x
por $x=~/./gs
.
Todo Perl embutido retorna algo. print
retorna 1, por exemplo, para indicar E / S bem-sucedida. Se você precisar inicializar $_
com um valor verdadeiro, por exemplo, $_=print$foo
permite matar dois coelhos com uma cajadada só.
Quase todas as declarações no Perl podem ser escritas como uma expressão, permitindo que sejam usadas em uma variedade maior de contextos. Várias instruções podem se tornar várias expressões encadeadas por vírgulas. Os testes podem ser feitos com operadores de curto-circuito ?:
&&
||
e também com and
e or
, que fazem a mesma coisa, mas com precedência menor do que todos os outros operadores (incluindo a atribuição). Os loops podem ser feitos via map
ou grep
. Mesmo palavras-chave como next
, last
e return
pode ser usado em um contexto expressão, mesmo que eles não voltar! Tendo em mente esses tipos de transformações, você tem a oportunidade de substituir blocos de código por expressões que podem ser inseridas em uma variedade maior de contextos.
$_=print""
é mais curto que$_=print$foo
.$foo
. Caso contrário,$_=1
é muito menor$_=print""
e tem o mesmo efeito.$x
? Caso contrário, você poderia apenas fazer/./gs
e/./g
.Abuse as variáveis especiais do Perl!
Conforme observado em uma resposta anterior,
$/
e$"
são inicializados por padrão para"\n"
e" "
, respectivamente.$,
e$\
são definidos comoundef
padrão e são 3 caracteres mais curtos.Definir
$\
um valor fará com que ele seja anexado a todosprint
. Por exemplo:perl -ple '$\="=".hex.$/'
é um prático conversor hexadecimal para decimal.Se você não estiver lendo arquivos da linha de comando, poderá usar a
-i
opção de linha de comando como um canal extra para inserir uma string. Seu valor será armazenado em$^I
.$=
força o que for atribuído a ele como um número inteiro. Tente executarperl -ple '$_=$==$_'
e dar várias entradas. Da mesma forma,$-
força seu valor a ser um número inteiro não negativo (ou seja, um traço à esquerda é tratado como um caractere não numérico).Você pode usar
$.
como um sinalizador booleano que é redefinido automaticamente para um valor verdadeiro (diferente de zero) em todas as iterações de umwhile(<>)
loop.fonte
-n
e colchetes incomparáveisÉ sabido que a opção de linha de comando
-n
pode ser usada para executar o script uma vez para cada linha.perl --help
diz:O que não diz explicitamente é que o Perl não assume apenas um loop ao redor do programa; ele literalmente envolve
while (<>) { ... }
em torno dele.Dessa forma, os seguintes comandos são equivalentes entre si:
-p
e colchetes incomparáveisDe maneira semelhante ao acima, o
-p
comutador envolvewhile (<>) { ... ; print }
o programa.Ao usar colchetes incomparáveis,
perl -p 'code}{morecode'
será impresso apenas uma vez após a execuçãocode
de todas as linhas de entrada, seguidas pormorecode
.Como não
$_
é definido quandomorecode;print
é executado, o separador de registros de saída$\
pode ser usado com abuso para imprimir a saída real.Por exemplo
lê um número por linha de STDIN e imprime sua soma.
fonte
#!perl -n
a primeira linha, certo?-p
e$\
) pela primeira vez em uma das respostas Perl do @primo . Ler suas respostas é uma boa dica do Perl por si só.}for(...){
em entre as chaves é muitas vezes bastante útil, bem como, por exemplo codegolf.stackexchange.com/a/25632Use
$_
para eliminar referências escalares. É a variável especial que é usada como padrão pela maioria das funções, e deixar de fora os parâmetros é um atalho para fazer referência a essa variável.Ao mudar
$n
para$_
, você pode mudar$n=<>;chop$n;print$n
para$_=<>;chop;print
Aqui, a
print
função imprime o conteúdo de$_
por padrão echop
também funciona$_
.fonte
$_=<>;
obrigatório, não<>;
lê a linha$_
automaticamente?$_=<>;print
e<>;print
. O primeiro repete para mim o que eu digito, enquanto o outro não.print while(<>)
. Não tenho certeza se é um caso especial ou há alguma lógica coerente por trás dele, nem<>
da parteperlop
nemwhile
parteperlsyn
parecem mencionar esse comportamento.while(<>)
é um caso especial, documentado em perlsyn, operadores de E / S: 'Se e somente se o símbolo de entrada for a única coisa dentro da condição de uma declaração "while" (mesmo se disfarçada de "for (;;)" circular), o valor é automaticamente atribuído à variável global $ _, destruindo tudo o que estava lá anteriormente ".Use as variáveis especiais do Perl sempre que possível, por exemplo:
$"
vez de" "
$/
vez de"\n"
Eles têm o benefício adicional de serem um identificador de um caractere garantido, com a ajuda do lexer. Isso possibilita colá-lo à palavra-chave a seguir, como em:
print$.for@_
A lista de todas as variáveis especiais está disponível aqui: Variáveis Especiais
fonte
Não use
qw
. Isso é desperdício de dois caracteres que poderiam ser usados da melhor maneira. Por exemplo, não escreva o seguinte.Em vez disso, use palavras de barras.
Ou, se você não pode usar palavras de barra, use a
glob
sintaxe.glob
A sintaxe também pode ser usada para efeitos interessantes.fonte
Use modificadores de instrução em vez de instruções compostas.
Instruções compostas tendem a exigir parênteses para o argumento e chaves para o bloco, enquanto modificadores de instruções não precisam de nenhuma.
Comparar:
$a++,$b++while$n--
vswhile($n--){$a++;$b++}
chop$,if$c
vsif($c){chop$,}
Observe que o último exemplo está vinculado
$c&&chop$,
, mas começa realmente a brilhar na maioria das operações com várias instruções. Basicamente, qualquer coisa que perca precedência do operador&&
.fonte
Não
use strict
. (não me cite, o contexto PCG.SE é meio importante) E, mais importante, não codifique como se estivesse sob rigoroso. Os suspeitos do costume:my
declare variáveis se puder evitá-lo. As únicas variáveis que realmente precisammy
são aquelas que você deseja definir com escopo lexical. Isso quase não ocorre no golfe, onde você não precisa de proteção de escopo e tende a controlar totalmente a recursão.fonte
print hello
não vai funcionar. Na verdade, significaprint hello $_
(imprimir$_
em arquivohello
).print
, e agora eu não posso encontrar um bom e pequeno exemplo)Tenho certeza de que alguns deles têm nomes formais e simplesmente não os conheço.
print $n++ while ($n < 10)
$var = join('',<>)
print ('X'*10) . "\n";
é maior queprint ('X'*10) . $/;
say
função do Perl é menor queprint
, mas você precisará executar o código em-E
vez de-e
a..z
ou mesmoaa..zz
. Se necessário como uma string, usejoin
.$z = 'z'; print ++$z;
será exibidoaa
É tudo o que consigo pensar agora. Eu posso adicionar um pouco mais tarde.
fonte
print ('X'*10) . $/;
deveria fazer? Para mim, imprime0
e não há nova linha. Por um lado, os parênteses se tornam um argumento de chamada no estilo de funçãoprint
, que se liga mais estreitamente que.
. E você quis dizer emx
vez de*
ou algo assim?while
,join'',<>;
também funciona sem eles.Use caracteres que não sejam palavras como nomes de variáveis
Usando
$%
vez de$a
pode permitir que você coloque o nome da variável para a direita ao lado de umif
,for
ouwhile
construir como em:@r=(1,2,3,4,5);$%=4;
print$_*$%for@r
Muitos podem ser usados, mas verifique os documentos e a resposta do @ BreadBox para quais têm efeitos mágicos!
Use map quando não puder usar modificadores de instrução
Se você não pode usar modificadores de declaração de acordo com a resposta de @ JB , o mapa pode salvar um byte:
for(@c){}
vs.map{}@c;
e é útil se você deseja fazer iterações aninhadas, pois é possível colocar
for
loops postfix dentro do arquivomap
.Use todas as variáveis mágicas de expressão regular
O Perl possui variáveis mágicas para 'texto antes da correspondência' e 'texto após correspondência', portanto, é possível dividir em grupos de dois com potencialmente menos caracteres:
Isso também pode funcionar bem como um substituto para
substr
:Se você precisar do conteúdo da partida,
$&
pode ser usado, por exemplo:Substituir subs por nomes longos por um nome mais curto
Se você ligar, digamos
print
quatro ou mais vezes em seu código (isso obviamente varia com a duração da rotina que você está chamando), substitua-o por um subnome mais curto:vs.
Substituir incrementadores / decrementadores condicionais
Se você tiver um código como:
você pode usar:
em vez disso, salve alguns bytes.
Converter em número inteiro
Se você não está atribuindo a uma variável e não pode usar a dica da caixa de pão , pode usar a expressão
0|
:No entanto, vale a pena notar que você não precisa usar um número inteiro para acessar um índice de matriz:
fonte
redo
adiciona comportamento de loop a um bloco semfor
ouwhile
.{redo}
é um loop infinito.fonte
Não coloque parênteses em chamadas de função.
O Perl permite chamar uma função conhecida (principal ou predefinida) usando a
NAME LIST
sintaxe. Isso permite que você solte o&
sigilo (se você ainda o estiver usando) e os parênteses.Por exemplo:
$v=join'',<>
Documentação completa
fonte
Tente usar o valor de uma expressão de atribuição, da seguinte maneira:
Isso funciona porque
$n
há 2 caracteres no Perl. Você pode alterar$n
para()
sem nenhum custo e economizar 1 ponto e vírgula movendo a atribuição entre parênteses.fonte
Você pode executar várias instruções diferentes dentro da lógica ternária aninhada.
Suponha que você tenha um grande
if
-elsif
comunicado. Pode ser qualquer lógica e qualquer número de instruções.Você pode usar
(cmd1, cmd2, cmd3)
dentro do operador ternário para executar todos os comandos.Aqui está um exemplo fictício:
fonte
Use em
select(undef,undef,undef,$timeout)
vez deTime::HiRes
(Retirado de https://stackoverflow.com/a/896928/4739548 )
Muitos desafios exigem que você durma com maior precisão do que números inteiros.
select()
O argumento de tempo limite pode fazer exatamente isso.é muito mais eficiente que:
O primeiro tem apenas 20 bytes, enquanto o último ocupa 39. No entanto, o primeiro exige que você não esteja usando
$u
e nunca o definiu.Se você vai usá-lo muito, a importação
Time::HiRes
compensa, mas se você precisar apenas uma vez, o usoselect($u,$u,$u,0.1)
salva 19 bytes, o que é definitivamente uma melhoria na maioria dos casos.fonte
Encurte suas declarações de impressão
A menos que o desafio especifique o contrário, não é necessário rastrear novas linhas.
Nosso 'desafio' diz 'gera um número aleatório de 0 a 9 para STDOUT'. Podemos pegar este código (28 bytes):
E reduza para isso (25 bytes):
simplesmente imprimindo a variável. Este último se aplica apenas a esse desafio especificamente (19 bytes):
mas isso só funciona quando você não precisa fazer nada com a variável entre atribuição e impressão.
fonte
Use globs como literais de string
Ocasionalmente (geralmente quando se lida com desafios de quine ou de fonte restrita ), você se beneficia muito da capacidade de aninhar literais de strings. Normalmente, você faria isso com
q(…)
. No entanto, dependendo de quais caracteres você precisa dentro da string, você poderá salvar um byte e usar<…>
o operador glob. (Observe que o que está dentro dos colchetes angulares não pode parecer um identificador de arquivo e não pode ser expandido para uma lista de nomes de arquivos, o que significa que muitos caracteres não funcionarão corretamente.)fonte
Use a expressão regexe.
Uma ilustração decente disso é o seguinte código que forma a entrada em onda senoidal:
Como você pode ver, é uma maneira bastante compacta de iterar caracteres na entrada padrão. Você pode usar outra regex para alterar a maneira como as coisas são correspondidas.
fonte