TeX, 216 bytes (4 linhas, 54 caracteres cada)
Porque não se trata da contagem de bytes, é sobre a qualidade da saída digitada :-)
{\let~\catcode~`A13 \defA#1{~`#113\gdef}AGG#1{~`#1 13%
\global\let}GFF\elseGHH\fiAQQ{Q}AII{\ifxQ}AEE#1#2#3|{%
I#3#2#1FE{#1#2}#3|H}ADD#1#2|{I#1FE{}#1#2|H}ACC#1#2|{D%
#2Q|#1 }ABBH#1 {HI#1FC#1|BH}\gdef\S#1{\iftrueBH#1 Q }}
Experimente Online! (No verso; não tenho certeza de como funciona)
Arquivo de teste completo:
{\let~\catcode~`A13 \defA#1{~`#113\gdef}AGG#1{~`#1 13%
\global\let}GFF\elseGHH\fiAQQ{Q}AII{\ifxQ}AEE#1#2#3|{%
I#3#2#1FE{#1#2}#3|H}ADD#1#2|{I#1FE{}#1#2|H}ACC#1#2|{D%
#2Q|#1 }ABBH#1 {HI#1FC#1|BH}\gdef\S#1{\iftrueBH#1 Q }}
\S{swap the a first and last letters of each word}
pwas eht a tirsf dna tasl setterl fo hace dorw
\S{SWAP THE A FIRST AND LAST LETTERS OF EACH WORD}
\bye
Saída:
Para o LaTeX, você só precisa do padrão:
\documentclass{article}
\begin{document}
{\let~\catcode~`A13 \defA#1{~`#113\gdef}AGG#1{~`#1 13%
\global\let}GFF\elseGHH\fiAQQ{Q}AII{\ifxQ}AEE#1#2#3|{%
I#3#2#1FE{#1#2}#3|H}ADD#1#2|{I#1FE{}#1#2|H}ACC#1#2|{D%
#2Q|#1 }ABBH#1 {HI#1FC#1|BH}\gdef\S#1{\iftrueBH#1 Q }}
\S{swap the a first and last letters of each word}
pwas eht a tirsf dna tasl setterl fo hace dorw
\S{SWAP THE A FIRST AND LAST LETTERS OF EACH WORD}
\end{document}
Explicação
TeX é uma fera estranha. Ler o código normal e entendê-lo é um feito por si só. Compreender o código TeX ofuscado vai alguns passos adiante. Vou tentar tornar isso compreensível para as pessoas que também não conhecem o TeX. Portanto, antes de começar, aqui estão alguns conceitos sobre o TeX para facilitar o acompanhamento:
Para iniciantes (não tão) absolutos em TeX
Primeiro, e o item mais importante nesta lista: o código não precisa estar em forma de retângulo, mesmo que a cultura pop possa levá-lo a pensar isso .
TeX é uma linguagem de expansão de macro. Você pode, por exemplo, definir \def\sayhello#1{Hello, #1!}
e escrever \sayhello{Code Golfists}
para fazer o TeX imprimir Hello, Code Golfists!
. Isso é chamado de “macro não limitada” e, para alimentá-lo como o primeiro (e único, neste caso) parâmetro, você o coloca entre chaves. O TeX remove esses chavetas quando a macro pega o argumento. Você pode usar até 9 parâmetros: \def\say#1#2{#1, #2!}
então \say{Good news}{everyone}
.
A contrapartida de macros undelimited são, sem surpresa, os delimitado :) Você poderia fazer a definição anterior um pouco mais semântico : \def\say #1 to #2.{#1, #2!}
. Nesse caso, os parâmetros são seguidos pelo chamado texto do parâmetro . Esse texto de parâmetro delimita o argumento da macro ( #1
é delimitado por ␣to␣
, espaços incluídos e #2
delimitado por .
). Após essa definição, você pode escrever \say Good news to everyone.
e expandir para Good news, everyone!
. Legal, não é? :) No entanto, um argumento delimitado é (citando o TeXbook ) "a sequência mais curta (possivelmente vazia) de tokens com {...}
grupos aninhados corretamente que é seguida na entrada por esta lista específica de tokens sem parâmetros". Isso significa que a expansão de\say Let's go to the mall to Martin
produzirá uma frase estranha. Neste caso, você precisa de “esconder” o primeiro ␣to␣
com {...}
: \say {Let's go to the mall} to Martin
.
Por enquanto, tudo bem. Agora as coisas começam a ficar estranhas. Quando o TeX lê um caractere (que é definido por um "código de caractere"), ele atribui a esse caractere um "código de categoria" (código de categoria para amigos :) que define o que esse caractere significa. Essa combinação de código de caractere e categoria cria um token (mais sobre isso aqui , por exemplo). Os que nos interessam aqui são basicamente:
catcode 11 , que define tokens que podem compor uma sequência de controle (um nome elegante para uma macro). Por padrão, todas as letras [a-zA-Z] são catcode 11, para que eu possa escrever \hello
, que é uma única sequência de controle, enquanto \he11o
é a sequência de controle \he
seguida por dois caracteres 1
, seguida pela letra o
, porque 1
não é o código 11. Se eu a \catcode`1=11
partir desse momento \he11o
seria uma sequência de controle. Uma coisa importante é que os códigos de código são definidos quando o TeX vê o personagem pela primeira vez, e esse código de código é congelado ... PARA SEMPRE! (Termos e condições podem ser aplicadas)
catcode 12 , que são a maioria dos outros caracteres, como 0"!@*(?,.-+/
e assim por diante. Eles são o tipo menos especial de código de gato, pois servem apenas para escrever coisas no papel. Mas ei, quem usa o TeX para escrever?!? (novamente, termos e condições podem ser aplicados)
catcode 13 , que é o inferno :) Realmente. Pare de ler e faça algo fora de sua vida. Você não quer saber o que é o catcode 13. Já ouviu falar da sexta-feira, 13? Adivinhe de onde veio esse nome! Continue por sua conta e risco! Um caractere catcode 13, também chamado de "ativo", não é mais apenas um personagem, é uma macro em si! Você pode defini-lo para ter parâmetros e expandir para algo como vimos acima. Depois que \catcode`e=13
você acha que pode fazer \def e{I am the letter e!}
, MAS. VOCÊS. NÃO PODES! e
não é mais uma carta, então \def
não é o que \def
você sabe, é \d e f
! Oh, escolha outra letra que você diz? OK! \catcode`R=13 \def R{I am an ARRR!}
. Muito bem, Jimmy, tente! Ouso fazer isso e escrevo um R
no seu código! Isso é o que é um código de gato 13. EU ESTOU CALMO! Vamos continuar.
Ok, agora ao agrupamento. Isso é bastante direto. Quaisquer que sejam as atribuições ( \def
é uma operação de atribuição \let
(entraremos nela)) são feitas em um grupo e são restauradas para o que eram antes do início do grupo, a menos que a atribuição seja global. Existem várias maneiras de iniciar grupos, um deles com os códigos de gato 1 e 2 (oh, códigos de gato novamente). Por padrão, {
é catcode 1, ou begin-group, e }
é catcode 2, ou end-group. Um exemplo: \def\a{1} \a{\def\a{2} \a} \a
Isso imprime 1 2 1
. Fora do grupo \a
estava 1
, em seguida, foi redefinido para dentro 2
e, quando o grupo terminou, foi restaurado para 1
.
A \let
operação é outra operação de atribuição como \def
, mas bastante diferente. Com \def
você, defina macros que serão expandidas para outras coisas, e \let
crie cópias de coisas já existentes. Após \let\blub=\def
(o =
é opcional), você pode alterar o início do e
exemplo do item de código de gato 13 acima para \blub e{...
e se divertir com esse. Ou melhor, em vez de quebrar coisas que você pode corrigir (se você olhar para isso!) O R
exemplo: \let\newr=R \catcode`R=13 \def R{I am an A\newr\newr\newr!}
. Pergunta rápida: você poderia renomear para \newR
?
Finalmente, os chamados "espaços espúrios". Esse é um tópico tabu, porque há pessoas que afirmam que a reputação conquistada no TeX - LaTeX Stack Exchange , respondendo a perguntas de "espaços espúrios", não deve ser considerada, enquanto outras discordam de todo o coração. Com quem você concorda? Faça suas apostas! Enquanto isso: o TeX entende uma quebra de linha como um espaço. Tente escrever várias palavras com uma quebra de linha (não uma linha vazia ) entre elas. Agora adicione um %
no final dessas linhas. É como se você estivesse “comentando” esses espaços de fim de linha. É isso aí :)
(Mais ou menos) desregulamentando o código
Vamos tornar esse retângulo em algo (sem dúvida) mais fácil de seguir:
{
\let~\catcode
~`A13
\defA#1{~`#113\gdef}
AGG#1{~`#113\global\let}
GFF\else
GHH\fi
AQQ{Q}
AII{\ifxQ}
AEE#1#2#3|{I#3#2#1FE{#1#2}#3|H}
ADD#1#2#3|{I#2FE{#1}#2#3|H}
ACC#1#2|{D{}#2Q|#1 }
ABBH#1 {HI#1FC#1|BH}
\gdef\S#1{\iftrueBH#1 Q }
}
Explicação de cada etapa
cada linha contém uma única instrução. Vamos um por um, dissecando-os:
{
Primeiro, iniciamos um grupo para manter algumas alterações (ou seja, alterações no código do gato) local, para que elas não atrapalhem o texto de entrada.
\let~\catcode
Basicamente, todos os códigos de ofuscação TeX começam com esta instrução. Por padrão, no TeX e no LaTeX, o ~
caractere é o caractere ativo que pode ser transformado em macro para uso posterior. E a melhor ferramenta para esquisitificar o código TeX são as alterações no código do gato, portanto essa geralmente é a melhor escolha. Agora, em vez de \catcode`A=13
podermos escrever ~`A13
(o =
é opcional):
~`A13
Agora a letra A
é um caractere ativo, e podemos defini-la para fazer algo:
\defA#1{~`#113\gdef}
A
agora é uma macro que recebe um argumento (que deve ser outro caractere). Primeiro, o código do argumento é alterado para 13 para torná-lo ativo: ~`#113
(substitua ~
por \catcode
e adicione um =
e você tem :) \catcode`#1=13
. Finalmente, deixa um \gdef
(global \def
) no fluxo de entrada. Em resumo, A
ativa outro personagem e inicia sua definição. Vamos tentar:
AGG#1{~`#113\global\let}
AG
primeiro "ativa" G
e faz \gdef
, que seguido pelo próximo G
inicia a definição. A definição de G
é muito semelhante à de A
, exceto que, em vez disso \gdef
, faz a \global\let
(não há \glet
como o \gdef
). Em resumo, G
ativa um personagem e faz com que seja outra coisa. Vamos criar atalhos para dois comandos que usaremos mais adiante:
GFF\else
GHH\fi
Agora, em vez de \else
e \fi
podemos simplesmente usar F
e H
. Muito mais curto :)
AQQ{Q}
Agora usamos A
novamente para definir outra macro Q
,. A declaração acima basicamente funciona (em um idioma menos ofuscado) \def\Q{\Q}
. Esta não é uma definição muito interessante, mas tem um recurso interessante. A menos que você queira quebrar algum código, a única macro que se expande Q
é Q
ela mesma, então ela age como um marcador exclusivo (é chamado de quark ). Você pode usar o \ifx
condicional para testar se o argumento de uma macro é tão quark com \ifx Q#1
:
AII{\ifxQ}
para ter certeza de que encontrou esse marcador. Observe que nesta definição eu removi o espaço entre \ifx
e Q
. Normalmente, isso levaria a um erro (observe que o destaque da sintaxe acha que isso \ifxQ
é uma coisa), mas como agora Q
é o código de código 13, não pode formar uma sequência de controle. Tenha cuidado, no entanto, para não expandir esse quark ou você ficará preso em um loop infinito, porque se Q
expande para Q
qual se expande para Q
qual ...
Agora que as preliminares estão concluídas, podemos ir ao algoritmo apropriado para pwas eht setterl. Devido à tokenização do TeX, o algoritmo deve ser escrito ao contrário. Isso ocorre porque, no momento em que você faz uma definição, o TeX tokeniza (atribui códigos de gato) aos caracteres na definição usando as configurações atuais; por exemplo, se eu fizer:
\def\one{E}
\catcode`E=13\def E{1}
\one E
a saída é E1
, enquanto que se eu alterar a ordem das definições:
\catcode`E=13\def E{1}
\def\one{E}
\one E
a saída é 11
. Isso ocorre porque no primeiro exemplo E
, a definição foi simbolizada como uma letra (código 11) antes da alteração do código, portanto sempre será uma letra E
. No segundo exemplo, no entanto, E
foi ativado pela primeira vez e somente então \one
foi definido, e agora a definição contém o código de gato 13 ao E
qual se expande 1
.
No entanto, ignorarei esse fato e reordenarei as definições para ter uma ordem lógica (mas não funcionando). Nos parágrafos seguintes, você pode assumir que as letras B
, C
, D
, e E
são ativos.
\gdef\S#1{\iftrueBH#1 Q }
(observe que houve um pequeno bug na versão anterior, ele não continha o espaço final na definição acima. Eu só o notei enquanto escrevia isso. Continue lendo e você verá por que precisamos desse para finalizar corretamente a macro. )
Primeiro, definimos a macro no nível do usuário \S
,. Esse não deve ser um caractere ativo para ter uma sintaxe amigável (?); Portanto, a macro para gwappins eht setterl é \S
. A macro começa com uma condicional sempre verdadeira \iftrue
(em breve ficará claro o porquê) e depois chama a B
macro seguida por H
(que definimos anteriormente \fi
) para corresponder a \iftrue
. Então deixamos o argumento da macro #1
seguido por um espaço e pelo quark Q
. Suponha que usamos \S{hello world}
, então o fluxo de entradadeve ficar assim: \iftrue BHhello world Q␣
(Substituí o último espaço por um ␣
para que a renderização do site não o coma, como fiz na versão anterior do código). \iftrue
é verdade, então se expande e nos resta BHhello world Q␣
. O TeX não remove o \fi
( H
) depois que a condicional é avaliada; em vez disso, deixa-o lá até que ele \fi
seja realmente expandido. Agora a B
macro está expandida:
ABBH#1 {HI#1FC#1|BH}
B
é uma macro delimitada cujo texto do parâmetro é H#1␣
, portanto, o argumento é o que estiver entre H
e um espaço. Continuando o exemplo acima do fluxo de entrada antes da expansão de B
is BHhello world Q␣
. B
é seguido por H
, como deveria (caso contrário, o TeX geraria um erro), então o próximo espaço é entre hello
e world
, assim #1
é a palavra hello
. E aqui temos que dividir o texto de entrada nos espaços. Yay: D A expansão da B
remove tudo acima para o primeiro espaço a partir do fluxo de entrada e substitui por HI#1FC#1|BH
com #1
sendo hello
: HIhelloFChello|BHworld Q␣
. Observe que há um novo BH
posteriormente no fluxo de entrada para fazer uma recursão final deB
e processe palavras posteriores. Depois que essa palavra é processada, B
processa a próxima palavra até que a palavra a ser processada seja o quark Q
. O último espaço a seguir Q
é necessário porque a macro delimitada B
requer um no final do argumento. Com a versão anterior (consulte o histórico de edições), o código se comportaria mal se você o usasse \S{hello world}abc abc
(o espaço entre os abc
s desapareceria).
OK, de volta para o fluxo de entrada: HIhelloFChello|BHworld Q␣
. Primeiro, há o H
( \fi
) que completa a inicial \iftrue
. Agora temos o seguinte (pseudocodificado):
I
hello
F
Chello|B
H
world Q␣
O I...F...H
pensamento é realmente uma \ifx Q...\else...\fi
estrutura. O \ifx
teste verifica se o (primeiro símbolo da) palavra capturada é o Q
quark. Se é não há mais nada a fazer e os termina a execução, caso contrário, o que resta é: Chello|BHworld Q␣
. Agora C
é expandido:
ACC#1#2|{D#2Q|#1 }
O primeiro argumento de C
se não delimitado, de modo a não ser que se preparou-lo será um único modo, o segundo argumento é delimitado por |
, assim, após a expansão de C
(com #1=h
e #2=ello
) o fluxo de entrada é: DelloQ|h BHworld Q␣
. Observe que outro |
é colocado lá, e o h
de hello
é colocado depois disso. Metade da troca é feita; a primeira letra está no final. No TeX, é fácil pegar o primeiro token de uma lista de tokens. Uma macro simples \def\first#1#2|{#1}
recebe a primeira letra quando você usa \first hello|
. O último é um problema, porque o TeX sempre pega a lista de tokens “menor, possivelmente vazia” como argumento, por isso precisamos de algumas soluções alternativas. O próximo item na lista de tokens é D
:
ADD#1#2|{I#1FE{}#1#2|H}
Essa D
macro é uma das soluções alternativas e é útil no único caso em que a palavra tem uma única letra. Suponha que ao invés de hello
nós tivéssemos x
. Neste caso o fluxo de entrada seria DQ|x
, em seguida, D
se expandir (com #1=Q
, e #2
esvaziar) a: IQFE{}Q|Hx
. Isso é semelhante ao bloco I...F...H
( \ifx Q...\else...\fi
) B
, que verá que o argumento é o quark e interromperá a execução, deixando apenas x
para a digitação. Em outros casos (voltando ao hello
exemplo), D
seria expandir (com #1=e
e #2=lloQ
) para: IeFE{}elloQ|Hh BHworld Q␣
. Novamente, o I...F...H
irá verificar se há Q
, mas irá falhar e levar o \else
ramo: E{}elloQ|Hh BHworld Q␣
. Agora, o último pedaço dessa coisa, oE
a macro expandiria:
AEE#1#2#3|{I#3#2#1FE{#1#2}#3|H}
O texto do parâmetro aqui é bastante semelhante a C
e D
; o primeiro e o segundo argumentos não são limitados e o último é delimitado por |
. A aparência do fluxo de entrada, como este: E{}elloQ|Hh BHworld Q␣
, em seguida, E
expande-se (com #1
vazio, #2=e
, e #3=lloQ
): IlloQeFE{e}lloQ|HHh BHworld Q␣
. Outro I...F...H
bloco de cheques para o quark (que vê l
e volta false
): E{e}lloQ|HHh BHworld Q␣
. Agora E
se expande novamente (com #1=e
vazio, #2=l
e #3=loQ
): IloQleFE{el}loQ|HHHh BHworld Q␣
. E mais uma vez I...F...H
. A macro faz mais algumas iterações até que Q
finalmente seja encontrada e a true
ramificação seja obtida: E{el}loQ|HHHh BHworld Q␣
-> IoQlelFE{ell}oQ|HHHHh BHworld Q␣
-> E{ell}oQ|HHHHh BHworld Q␣
-> IQoellFE{ello}Q|HHHHHh BHworld Q␣
. Agora, o quark é encontrado e se expande condicionais para: oellHHHHh BHworld Q␣
. Ufa.
Oh, espere, o que são esses? CARTAS NORMAIS? Oh garoto! As letras estão finalmente encontrado e TeX escreve para baixo oell
, em seguida, um monte de H
( \fi
) são encontrados e expandido (ou nada), deixando o fluxo de entrada com: oellh BHworld Q␣
. Agora, a primeira palavra tem a primeira e a última letras trocadas e o que o TeX encontra a seguir é o outro B
para repetir todo o processo para a próxima palavra.
}
Finalmente, terminamos o grupo iniciado lá, para que todas as tarefas locais sejam desfeitas. As atribuições locais são as mudanças catcode das letras A
, B
, C
, ... que foram feitas macros para que eles retornam à sua carta significado normal e pode ser usado com segurança no texto. E é isso. Agora, a \S
macro definida lá atrás acionará o processamento do texto como acima.
Uma coisa interessante sobre esse código é que ele é totalmente expansível. Ou seja, você pode usá-lo com segurança na movimentação de argumentos sem se preocupar com a explosão. Você pode até usar o código para verificar se a última letra de uma palavra é igual à segunda (por qualquer motivo que você precise) em um \if
teste:
\if\S{here} true\else false\fi % prints true (plus junk, which you would need to handle)
\if\S{test} true\else false\fi % prints false
Desculpe pela (provavelmente muito) explicação detalhada. Tentei deixar o mais claro possível também para os não TeXies :)
Resumo para o impaciente
A macro \S
precede a entrada com um caractere ativo B
que pega listas de tokens delimitadas por um espaço final e as passa para C
. C
pega o primeiro token nessa lista e o move para o final da lista de tokens e expande D
com o que resta. D
verifica se "o que resta" está vazio; nesse caso, uma palavra de uma letra foi encontrada, então não faça nada; caso contrário, se expande E
. E
percorre a lista de tokens até encontrar a última letra da palavra, quando é encontrada deixa a última letra, seguida pelo meio da palavra, seguida pela primeira letra deixada no final do fluxo de tokens por C
.
Hello, world!
torna-se,elloH !orldw
(trocando pontuação como uma letra) ouoellH, dorlw!
(mantendo a pontuação no lugar)?