TeX, 216 octets (4 lignes, 54 caractères chacune)
Parce qu'il ne s'agit pas du nombre d'octets, il s'agit de la qualité de la sortie de composition :-)
{\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 }}
Essayez-le en ligne! (Au verso; je ne sais pas comment cela fonctionne)
Fichier de test complet:
{\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
Sortie:

Pour LaTeX, vous avez juste besoin du passe-partout:
\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}
Explication
TeX est une étrange bête. Lire du code normal et le comprendre est un exploit en soi. La compréhension du code TeX obscurci va plus loin. Je vais essayer de rendre cela compréhensible pour les personnes qui ne connaissent pas aussi TeX, donc avant de commencer, voici quelques concepts sur TeX pour rendre les choses plus faciles à suivre:
Pour (pas tellement) les débutants absolus de TeX
Tout d' abord, et élément le plus important dans cette liste: le code ne pas avoir à être en forme rectangulaire, même si la culture pop pourrait vous amener à penser .
TeX est un langage d'expansion de macro. Vous pouvez, par exemple, définir \def\sayhello#1{Hello, #1!}puis écrire \sayhello{Code Golfists}pour que TeX s'imprime Hello, Code Golfists!. C'est ce qu'on appelle une «macro non délimitée», et pour lui donner le premier (et seulement, dans ce cas) paramètre, vous la mettez entre accolades. TeX supprime ces accolades lorsque la macro prend l'argument. Vous pouvez utiliser jusqu'à 9 paramètres: \def\say#1#2{#1, #2!}alors \say{Good news}{everyone}.
La contrepartie de macros sont non délimitées, sans surprise, les délimité :) Vous pouvez faire la définition précédente un peu plus sémantiquement : \def\say #1 to #2.{#1, #2!}. Dans ce cas, les paramètres sont suivis d'un texte dit de paramètres . Un tel texte de paramètre délimite l'argument de la macro ( #1est délimité par ␣to␣, espaces inclus et #2est délimité par .). Après cette définition, vous pouvez écrire \say Good news to everyone., qui se développera Good news, everyone!. Sympa, non? :) Cependant, un argument délimité est (en citant le TeXbook ) "la séquence de jetons la plus courte (éventuellement vide) avec des {...}groupes correctement imbriqués qui est suivie en entrée par cette liste particulière de jetons non paramétriques". Cela signifie que l'expansion de\say Let's go to the mall to Martinproduira une phrase bizarre. Dans ce cas , vous auriez besoin de « cacher » la première ␣to␣avec {...}: \say {Let's go to the mall} to Martin.
Jusqu'ici tout va bien. Maintenant, les choses commencent à devenir bizarres. Lorsque TeX lit un caractère (qui est défini par un «code de caractère»), il attribue à ce caractère un «code de catégorie» (catcode, pour les amis :) qui définit ce que ce caractère signifie. Cette combinaison de caractères et de code de catégorie fait un jeton (plus d'informations ici , par exemple). Ceux qui nous intéressent ici sont essentiellement:
catcode 11 , qui définit des jetons qui peuvent constituer une séquence de contrôle (un nom chic pour une macro). Par défaut, toutes les lettres [a-zA-Z] sont catcode 11, donc je peux écrire \hello, qui est une seule séquence de contrôle, tandis que \he11ola séquence de contrôle est \hesuivie de deux caractères 1, suivie de la lettre o, car ce 1n'est pas le catcode 11. Si je a \catcode`1=11, à partir de ce moment-là \he11oserait une séquence de contrôle. Une chose importante est que les catcodes sont définis lorsque TeX voit pour la première fois le personnage à portée de main, et ce catcode est gelé ... POUR TOUJOURS ! (Les termes et conditions peuvent s'appliquer)
catcode 12 , qui sont la plupart des autres caractères, tels que 0"!@*(?,.-+/et ainsi de suite. Ils sont le type de catcode le moins spécial car ils ne servent qu'à écrire des trucs sur le papier. Mais bon, qui utilise TeX pour écrire?!? (encore une fois, des conditions générales peuvent s'appliquer)
catcode 13 , qui est l'enfer :) Vraiment. Arrêtez de lire et allez faire quelque chose de votre vie. Vous ne voulez pas savoir ce qu'est le catcode 13. Avez-vous déjà entendu parler du vendredi 13? Devinez d'où il tire son nom! Continuez à vos risques et périls! Un caractère catcode 13, également appelé caractère «actif», n'est plus seulement un caractère, c'est une macro en soi! Vous pouvez le définir pour avoir des paramètres et développer quelque chose comme nous l'avons vu ci-dessus. Une fois que vous le faites , \catcode`e=13vous pensez que vous pouvez faire \def e{I am the letter e!}, MAIS. TOI. NE PEUX PAS! en'est plus une lettre, donc ce \defn'est pas ce que \defvous savez, ça l'est \d e f! Oh, choisissez une autre lettre que vous dites? D'accord! \catcode`R=13 \def R{I am an ARRR!}. Très bien, Jimmy, essaye! J'ose vous faire ça et écrire un Rdans votre code! C'est ce qu'est un catcode 13. JE SUIS CALME! Allons-nous en.
D'accord, maintenant au regroupement. C'est assez simple. Quelles que soient les affectations (il \defs'agit d'une opération d'affectation \let(nous y reviendrons) en est une autre) effectuées dans un groupe sont restaurées à ce qu'elles étaient avant le démarrage de ce groupe, sauf si cette affectation est globale. Il existe plusieurs façons de démarrer des groupes, l'un d'eux est avec les caractères catcode 1 et 2 (oh, catcodes à nouveau). Par défaut {est catcode 1, ou begin-group, et }est catcode 2, ou end-group. Un exemple: \def\a{1} \a{\def\a{2} \a} \acela s'imprime 1 2 1. En dehors du groupe \aétait 1, puis à l' intérieur , il a été redéfinie 2, et quand le groupe a pris fin, il a été restauré 1.
L' \letopération est une autre opération d'affectation comme \def, mais plutôt différente. Avec \defvous définissez des macros qui se développeront en choses, avec \letvous créez des copies de choses déjà existantes. Après \let\blub=\def(le =est facultatif), vous pouvez changer le début de l' eexemple de l'élément catcode 13 ci-dessus pour \blub e{...vous amuser avec celui-ci. Ou mieux, au lieu de casser des choses que vous pouvez fixer (chercheriez-vous à cela!) L' Rexemple: \let\newr=R \catcode`R=13 \def R{I am an A\newr\newr\newr!}. Question rapide: pourriez-vous renommer \newR?
Enfin, les soi-disant «espaces parasites». C'est une sorte de sujet tabou car il y a des gens qui prétendent que la réputation gagnée dans l' échange de piles TeX - LaTeX en répondant à des questions sur les «espaces parasites» ne devrait pas être prise en compte, tandis que d'autres sont en désaccord sans réserve. Avec qui êtes-vous d'accord? Placez vos paris! Pendant ce temps: TeX comprend un saut de ligne comme un espace. Essayez d'écrire plusieurs mots avec un saut de ligne (pas une ligne vide ) entre eux. Ajoutez maintenant un %à la fin de ces lignes. C'est comme si vous «commentiez» ces espaces de fin de ligne. C'est ça :)
(Sorte de) dé-golfer le code
Faisons de ce rectangle quelque chose (sans doute) plus facile à suivre:
{
\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 }
}
Explication de chaque étape
chaque ligne contient une seule instruction. Allons un par un, les disséquant:
{
Tout d'abord, nous commençons un groupe pour garder certaines modifications (à savoir les modifications de code de cat) locales afin qu'elles ne gâchent pas le texte d'entrée.
\let~\catcode
Fondamentalement, tous les codes d'obscurcissement TeX commencent par cette instruction. Par défaut, à la fois dans TeX simple et LaTeX, le ~caractère est le seul caractère actif qui peut être transformé en macro pour une utilisation ultérieure. Et le meilleur outil pour étrangler le code TeX sont les changements de catcode, c'est donc généralement le meilleur choix. Maintenant, au lieu de \catcode`A=13nous pouvons écrire ~`A13(le =est facultatif):
~`A13
Maintenant, la lettre Aest un caractère actif, et nous pouvons le définir pour faire quelque chose:
\defA#1{~`#113\gdef}
Aest maintenant une macro qui prend un argument (qui devrait être un autre caractère). Tout d'abord, le code cat de l'argument est changé en 13 pour le rendre actif: ~`#113(remplacez le ~par \catcodeet ajoutez un =et vous avez :) \catcode`#1=13. Enfin, il laisse un \gdef(global \def) dans le flux d'entrée. En bref, Arend un autre personnage actif et commence sa définition. Essayons:
AGG#1{~`#113\global\let}
AGle premier «s'active» Get le fait \gdef, ce qui, suivi du suivant, Gdémarre la définition. La définition de Gest très similaire à celle de A, sauf qu'au lieu de \gdefcela, il y a un \global\let(il n'y en a pas \gletcomme le \gdef). En bref, Gactive un personnage et en fait quelque chose d'autre. Faisons des raccourcis pour deux commandes que nous utiliserons plus tard:
GFF\else
GHH\fi
Maintenant, au lieu de \elseet \finous pouvons simplement utiliser Fet H. Plus court :)
AQQ{Q}
Maintenant , nous utilisons à Anouveau pour définir une autre macro, Q. La déclaration ci-dessus fait essentiellement (dans un langage moins obscur) \def\Q{\Q}. Ce n'est pas une définition terriblement intéressante, mais elle a une fonctionnalité intéressante. À moins que vous ne vouliez casser du code, la seule macro qui se développe Qest Qelle - même, elle agit donc comme un marqueur unique (on l'appelle un quark ). Vous pouvez utiliser le \ifxconditionnel pour tester si l'argument d'une macro est tel quark avec \ifx Q#1:
AII{\ifxQ}
vous pouvez donc être sûr que vous avez trouvé un tel marqueur. Notez que dans cette définition, j'ai supprimé l'espace entre \ifxet Q. Habituellement, cela entraînerait une erreur (notez que la mise en évidence de la syntaxe pense que \ifxQc'est une chose), mais comme il Qs'agit maintenant de catcode 13, il ne peut pas former une séquence de contrôle. Attention, cependant, à ne pas étendre ce quark ou vous serez coincé dans une boucle infinie car se Qdilate vers Qlequel se développe vers Qlequel ...
Maintenant que les préliminaires sont terminés, nous pouvons passer à l'algorithme approprié pour pwas eht setterl. En raison de la tokenisation de TeX, l'algorithme doit être écrit à l'envers. En effet, au moment où vous faites une définition, TeX va tokenize (attribuer des catcodes) aux caractères de la définition en utilisant les paramètres actuels, par exemple, si je le fais:
\def\one{E}
\catcode`E=13\def E{1}
\one E
la sortie est E1, alors que si je change l'ordre des définitions:
\catcode`E=13\def E{1}
\def\one{E}
\one E
la sortie est 11. En effet, dans le premier exemple, la Edéfinition a été symbolisée sous forme de lettre (catcode 11) avant le changement de catcode, ce sera donc toujours une lettre E. Dans le deuxième exemple, cependant, a Eété rendu actif pour la première fois, et seulement alors a \oneété défini, et maintenant la définition contient le code cat 13 Equi se développe 1.
Je vais cependant ignorer ce fait et réorganiser les définitions pour avoir un ordre logique (mais pas fonctionnel). Dans les paragraphes qui suivent , vous pouvez supposer que les lettres B, C, Det Esont actifs.
\gdef\S#1{\iftrueBH#1 Q }
(remarquez qu'il y avait un petit bug dans la version précédente, il ne contenait pas l'espace final dans la définition ci-dessus. Je l'ai seulement remarqué en écrivant ceci. Lisez la suite et vous verrez pourquoi nous avons besoin de celui-ci pour terminer correctement la macro. ) Tout d'
abord , nous définissons la macro-niveau utilisateur, \S. Celui-ci ne doit pas être un caractère actif pour avoir une syntaxe conviviale (?), Donc la macro pour gwappins eht setterl est \S. La macro commence par un conditionnel toujours vrai \iftrue(il sera bientôt clair pourquoi), puis appelle la Bmacro suivie de H(que nous avons définie précédemment comme étant \fi) pour correspondre à \iftrue. Ensuite, nous laissons l'argument de la macro #1suivi d'un espace et du quark Q. Supposons que nous utilisons \S{hello world}, alors le flux d'entréedevrait ressembler à ceci:\iftrue BHhello world Q␣(J'ai remplacé le dernier espace par un ␣pour que le rendu du site ne le mange pas, comme je le faisais dans la version précédente du code). \iftrueest vrai, donc il se développe et nous nous retrouvons avec BHhello world Q␣. TeX ne supprime pas le \fi( H) après l'évaluation du conditionnel, mais le laisse là jusqu'à ce que le \fisoit réellement développé. Maintenant, la Bmacro est développée:
ABBH#1 {HI#1FC#1|BH}
Best une macro délimitée dont le texte du paramètre est H#1␣, donc l'argument est tout ce qui est entre Het un espace. Poursuivant l'exemple au-dessus du flux d'entrée avant l'expansion de Bis BHhello world Q␣. Best suivi H, comme il se doit (sinon TeX soulèverait une erreur), alors l'espace suivant est entre helloet world, #1le mot aussi hello. Et ici, nous devons diviser le texte d'entrée dans les espaces. Yay: D L'expansion de BEnlève tout jusqu'au premier espace à partir du flux d'entrée et remplace par HI#1FC#1|BHd' #1être hello: HIhelloFChello|BHworld Q␣. Notez qu'il y a un nouveau BHplus tard dans le flux d'entrée, pour faire une récursion de queue deBet traiter les mots ultérieurs. Une fois ce mot traité, il Btraite le mot suivant jusqu'à ce que le mot à traiter soit le quark Q. Le dernier espace après Qest nécessaire car la macro délimitée en B requiert un à la fin de l'argument. Avec la version précédente (voir l'historique des modifications), le code se comporterait mal si vous l'utilisiez \S{hello world}abc abc(l'espace entre les abcs disparaîtrait).
OK, retour au flux d'entrée: HIhelloFChello|BHworld Q␣. Il y a d'abord le H( \fi) qui complète l'initiale \iftrue. Maintenant, nous avons ceci (pseudocodé):
I
hello
F
Chello|B
H
world Q␣
La I...F...Hréflexion est en fait une \ifx Q...\else...\fistructure. Le \ifxtest vérifie si le (premier jeton du) mot saisi est le Qquark. S'il est il n'y a rien d' autre à faire et les termine d'exécution, sinon ce qui reste est: Chello|BHworld Q␣. Maintenant Cest développé:
ACC#1#2|{D#2Q|#1 }
Le premier argument de Cest non délimité, de sorte que si contreventés ce sera un jeton unique, le second argument est délimitée par |, donc après l'expansion de la C(avec #1=het #2=ello) le flux d'entrée est la suivante : DelloQ|h BHworld Q␣. Remarquez qu'un autre |est mis là, et le hof helloest mis après. La moitié de l'échange est effectuée; la première lettre est à la fin. Dans TeX, il est facile de récupérer le premier jeton d'une liste de jetons. Une macro simple \def\first#1#2|{#1}obtient la première lettre lorsque vous utilisez \first hello|. Le dernier est un problème car TeX saisit toujours la liste de jetons "la plus petite, éventuellement vide" comme argument, nous avons donc besoin de quelques solutions. L'élément suivant dans la liste des jetons est D:
ADD#1#2|{I#1FE{}#1#2|H}
Cette Dmacro est l'une des solutions de contournement et elle est utile dans le seul cas où le mot a une seule lettre. Supposons qu'au lieu de hellonous x. Dans ce cas , le flux d'entrée serait DQ|xalors Délargirait (avec #1=Qet #2vide) à: IQFE{}Q|Hx. Ceci est similaire au bloc I...F...H( \ifx Q...\else...\fi) dans B, qui verra que l'argument est le quark et interrompra l'exécution en ne laissant que la xcomposition. Dans d' autres cas (retour à l' helloexemple), Délargirait (avec #1=eet #2=lloQ) à: IeFE{}elloQ|Hh BHworld Q␣. Encore une fois, le I...F...Hvérifiera Qmais échouera et prendre la \elsebranche: E{}elloQ|Hh BHworld Q␣. Maintenant, le dernier morceau de cette chose, leE la macro se développerait:
AEE#1#2#3|{I#3#2#1FE{#1#2}#3|H}
Le texte du paramètre ici est assez similaire à Cet D; les premier et deuxième arguments ne sont pas délimités et le dernier est délimité par |. Le flux d'entrée ressemble à ceci: E{}elloQ|Hh BHworld Q␣, puis se Edilate (avec #1vide, #2=e, et #3=lloQ): IlloQeFE{e}lloQ|HHh BHworld Q␣. Un autre I...F...Hbloc vérifie pour le quark (qui voit let retourne false): E{e}lloQ|HHh BHworld Q␣. Maintenant , se Edéveloppe à nouveau (avec #1=evide, #2=let #3=loQ): IloQleFE{el}loQ|HHHh BHworld Q␣. Et encore I...F...H. La macro effectue quelques itérations supplémentaires jusqu'à ce que le Qsoit finalement trouvé et que la truebranche soit prise: E{el}loQ|HHHh BHworld Q␣-> IoQlelFE{ell}oQ|HHHHh BHworld Q␣-> E{ell}oQ|HHHHh BHworld Q␣-> IQoellFE{ello}Q|HHHHHh BHworld Q␣. Maintenant , le quark se trouve et les conditionnels à se dilate: oellHHHHh BHworld Q␣. Phew.
Oh, attendez, qu'est-ce que c'est? LETTRES NORMALES? Oh mec! Les lettres sont finalement trouvés et TeX écrit vers le bas oell, puis un tas de H( \fi) se trouvent et étendu (rien) en laissant le flux d'entrée avec: oellh BHworld Q␣. Maintenant, le premier mot a la première et la dernière lettres échangées et ce que TeX trouve ensuite est l'autre Bpour répéter tout le processus pour le mot suivant.
}
Enfin, nous terminons le groupe commencé là-bas afin que toutes les affectations locales soient annulées. Les missions locales sont les changements de catcode des lettres A, B, C... qui ont été faites des macros pour qu'ils reviennent à leur signification normale de lettre et peuvent être utilisés en toute sécurité dans le texte. Et c'est tout. Maintenant, la \Smacro définie là-bas déclenchera le traitement du texte comme ci-dessus.
Une chose intéressante à propos de ce code est qu'il est entièrement extensible. Autrement dit, vous pouvez l'utiliser en toute sécurité pour déplacer des arguments sans craindre qu'il explose. Vous pouvez même utiliser le code pour vérifier si la dernière lettre d'un mot est la même que la seconde (pour une raison quelconque, vous en aurez besoin) dans un \iftest:
\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
Désolé pour l'explication (probablement beaucoup trop) verbeuse. J'ai essayé de le rendre aussi clair que possible pour les non TeXies :)
Résumé pour les impatients
La macro \Sajoute à l'entrée un caractère actif Bqui récupère les listes de jetons délimités par un espace final et les transmet à C. Cprend le premier jeton de cette liste et le déplace à la fin de la liste de jetons et se développe Davec ce qui reste. Dvérifie si «ce qui reste» est vide, auquel cas un mot d'une seule lettre a été trouvé, puis ne fait rien; sinon se développe E. Eparcourt la liste des jetons jusqu'à ce qu'il trouve la dernière lettre du mot, lorsqu'il le trouve, il laisse cette dernière lettre, suivi du milieu du mot, qui est ensuite suivi de la première lettre laissée à la fin du flux de jetons par C.
Hello, world!devient,elloH !orldw(permutation de la ponctuation en lettre) ouoellH, dorlw!(maintien de la ponctuation en place)?