TeX, 216 bytes (4 líneas, 54 caracteres cada una)
Debido a que no se trata del conteo de bytes, se trata de la calidad de la salida tipográfica :-)
{\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 }}
Pruébalo en línea! (Al dorso; no estoy seguro de cómo funciona)
Archivo de prueba 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
Salida:

Para LaTeX solo necesitas el repetitivo:
\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}
Explicación
TeX es una bestia extraña. Leer el código normal y comprenderlo es una hazaña en sí mismo. Comprender el código TeX ofuscado va unos pasos más allá. Trataré de hacer esto comprensible para las personas que no conocen TeX también, así que antes de comenzar, aquí hay algunos conceptos sobre TeX para que las cosas sean más fáciles de seguir:
Para principiantes de TeX (no tan)
Primero, y el elemento más importante en esta lista: el código no tiene que estar en forma de rectángulo, a pesar de que la cultura pop podría llevarlo a pensar que sí .
TeX es un lenguaje de macro expansión. Puede, como ejemplo, definir \def\sayhello#1{Hello, #1!}y luego escribir \sayhello{Code Golfists}para que TeX imprima Hello, Code Golfists!. Esto se llama una "macro no delimitada", y para alimentarlo el primer parámetro (y solo, en este caso) lo encierra entre llaves. TeX elimina esas llaves cuando la macro toma el argumento. Puede usar hasta 9 parámetros: \def\say#1#2{#1, #2!}entonces \say{Good news}{everyone}.
La contrapartida de macros no delimitada son, como era de esperar, los delimitado :) Se podría hacer que la definición anterior un poco más semántica : \def\say #1 to #2.{#1, #2!}. En este caso, los parámetros son seguidos por el llamado texto de parámetro . Tal texto parámetro delimita el argumento de la macro ( #1está delimitada por ␣to␣, espacios incluidos, y #2está delimitada por .). Después de esa definición puedes escribir \say Good news to everyone., que se expandirá a Good news, everyone!. Bien, ¿no es así? :) Sin embargo, un argumento delimitado es (citando el TeXbook ) "la secuencia más corta (posiblemente vacía) de tokens con {...}grupos correctamente anidados que se sigue en la entrada de esta lista particular de tokens sin parámetros". Esto significa que la expansión de\say Let's go to the mall to Martinproducirá una oración extraña. En este caso lo que se necesita para “ocultar” el primero ␣to␣con {...}: \say {Let's go to the mall} to Martin.
Hasta aquí todo bien. Ahora las cosas comienzan a ponerse raras. Cuando TeX lee un carácter (que se define mediante un "código de carácter"), asigna a ese carácter un "código de categoría" (código de gato, para amigos :) que define lo que significará ese carácter. Esta combinación de caracteres y código de categoría hace un token (más sobre eso aquí , por ejemplo). Los que nos interesan aquí son básicamente:
catcode 11 , que define tokens que pueden formar una secuencia de control (un nombre elegante para una macro). Por defecto, todas las letras [a-zA-Z] son código de gato 11, por lo que puedo escribir \hello, que es una secuencia de control única, mientras que \he11oes la secuencia de control \heseguida de dos caracteres 1, seguidos de la letra o, porque 1no es el código de gato 11. Si yo lo hizo \catcode`1=11, a partir de ese momento \he11osería una secuencia de control. Una cosa importante es que los códigos de gato se establecen cuando TeX ve por primera vez al personaje a mano, y ese código de gato se congela ... ¡PARA SIEMPRE! (Se pueden aplicar términos y condiciones)
catcode 12 , que son la mayoría de los otros caracteres, como, 0"!@*(?,.-+/etc. Son el tipo de código de gato menos especial, ya que solo sirven para escribir cosas en el papel. Pero oye, ¿quién usa TeX para escribir? (nuevamente, pueden aplicarse términos y condiciones)
catcode 13 , que es el infierno :) En serio. Deja de leer y ve a hacer algo fuera de tu vida. No quieres saber qué es el código de cat. 13. ¿Has oído hablar del viernes 13? ¡Adivina de dónde obtuvo su nombre! ¡Continúa bajo tu propia responsabilidad! Un carácter de código de gato 13, también llamado carácter "activo", ya no es solo un carácter, ¡es una macro en sí misma! Puede definirlo para que tenga parámetros y expandirlo a algo como vimos anteriormente. Después de lo \catcode`e=13que crees que puedes hacer \def e{I am the letter e!}, PERO. TÚ. ¡NO PODER! eya no es una carta, así \defque no es lo \defque sabes, ¡lo es \d e f! Oh, elige otra letra que dices? ¡Bueno! \catcode`R=13 \def R{I am an ARRR!}. Muy bien, Jimmy, ¡pruébalo! ¡Me atrevo a hacer eso y escribir un Ren su código! Eso es lo que es un catcode 13. ¡ESTOY CALMADO! Vamonos.
Bien, ahora a la agrupación. Esto es bastante sencillo. Cualesquiera asignaciones ( \defes una operación de asignación, \let(entraremos en ella) es otra) que se realizan en un grupo se restauran a lo que eran antes de que ese grupo comenzara a menos que esa asignación sea global. Hay varias formas de iniciar grupos, una de ellas es con los códigos de cat 1 y 2 caracteres (oh, catcodes nuevamente). Por defecto {es el código de gato 1, o grupo de inicio, y }es el código de gato 2, o grupo de finalización. Un ejemplo: \def\a{1} \a{\def\a{2} \a} \aesto imprime 1 2 1. Fuera del grupo \aera 1, a continuación, en su interior se redefinió a 2, y cuando el grupo terminó, fue restaurado a 1.
La \letoperación es otra operación de asignación similar \def, pero bastante diferente. Con \defusted define macros que se expandirán a cosas, con\let usted crea copias de cosas ya existentes. Después \let\blub=\def(el =es opcional) puede cambiar el inicio del eejemplo del elemento del código de cat. 13 anterior \blub e{...y divertirse con ese. O mejor, en lugar de romper cosas que se pueden arreglar (le mira eso!) Del Rejemplo: \let\newr=R \catcode`R=13 \def R{I am an A\newr\newr\newr!}. Pregunta rápida: ¿podrías cambiarle el nombre \newR?
Finalmente, los llamados "espacios espurios". Este es un tema tabú porque hay personas que afirman que la reputación ganada en TeX - LaTeX Stack Exchange al responder preguntas de "espacios espurios" no debe considerarse, mientras que otros están totalmente en desacuerdo. ¿Con quién estás de acuerdo? ¡Haga sus apuestas! Mientras tanto: TeX entiende un salto de línea como un espacio. Intente escribir varias palabras con un salto de línea (no una línea vacía ) entre ellas. Ahora agregue un %al final de estas líneas. Es como si estuvieras "comentando" estos espacios de fin de línea. Eso es :)
(Más o menos) descifrando el código
Hagamos que ese rectángulo se convierta en algo (posiblemente) más 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 }
}
Explicación de cada paso.
Cada línea contiene una sola instrucción. Vamos uno por uno, diseccionándolos:
{
Primero comenzamos un grupo para mantener algunos cambios (es decir, cambios de código de gato) locales para que no alteren el texto de entrada.
\let~\catcode
Básicamente, todos los códigos de ofuscación TeX comienzan con esta instrucción. Por defecto, tanto en TeX como en LaTeX, el ~carácter es el único carácter activo que puede convertirse en una macro para su uso posterior. Y la mejor herramienta para extrañar el código TeX son los cambios de código de gato, por lo que generalmente es la mejor opción. Ahora en lugar de \catcode`A=13podemos escribir ~`A13(el =es opcional):
~`A13
Ahora la letra Aes un carácter activo, y podemos definirla para hacer algo:
\defA#1{~`#113\gdef}
Aahora es una macro que toma un argumento (que debería ser otro carácter). Primero, el código de gato del argumento se cambia a 13 para activarlo: ~`#113(reemplace ~by \catcodey agregue an =y tiene :) \catcode`#1=13. Finalmente deja un \gdef(global \def) en la secuencia de entrada. En resumen, Aactiva otro personaje y comienza su definición. Vamos a intentarlo:
AGG#1{~`#113\global\let}
AGprimero "se activa" Gy lo hace \gdef, que luego sigue el siguiente Gcomienza la definición. La definición de Ges muy similar a la de A, excepto que en lugar de \gdefeso hace un \global\let(no hay un \gletcomo el \gdef). En resumen, Gactiva un personaje y lo convierte en otra cosa. Hagamos atajos para dos comandos que usaremos más adelante:
GFF\else
GHH\fi
Ahora en lugar de \elsey \fisimplemente podemos usar Fy H. Mucho más corto :)
AQQ{Q}
Ahora usamos Ade nuevo para definir otra macro, Q. La declaración anterior básicamente lo hace (en un lenguaje menos ofuscado) \def\Q{\Q}. Esta no es una definición terriblemente interesante, pero tiene una característica interesante. A menos que desee romper algún código, la única macro que se expande Qes a Qsí misma, por lo que actúa como un marcador único (se llama quark ). Puede usar el \ifxcondicional para probar si el argumento de una macro es tal quark con \ifx Q#1:
AII{\ifxQ}
así que puedes estar bastante seguro de haber encontrado ese marcador. Tenga en cuenta que en esta definición eliminé el espacio entre \ifxy Q. Por lo general, esto llevaría a un error (tenga en cuenta que el resaltado de sintaxis cree que \ifxQes una cosa), pero como ahora Qes el código de cat. 13, no puede formar una secuencia de control. Sin embargo, tenga cuidado de no expandir este quark o se quedará atrapado en un bucle infinito porque se Qexpande aQ que se expande a lo Qque ...
Ahora que los preliminares están terminados, podemos ir al algoritmo apropiado para establecer la configuración. Debido a la tokenización de TeX, el algoritmo debe escribirse al revés. Esto se debe a que en el momento en que realiza una definición, TeX tokenizará (asignará códigos de barras) a los caracteres de la definición utilizando la configuración actual, por ejemplo, si lo hago:
\def\one{E}
\catcode`E=13\def E{1}
\one E
la salida es E1, mientras que si cambio el orden de las definiciones:
\catcode`E=13\def E{1}
\def\one{E}
\one E
la salida es 11. Esto se debe a que en el primer ejemplo, Een la definición se tokenizó como una letra (catcode 11) antes del cambio de catcode, por lo que siempre será una letra E. Sin embargo, en el segundo ejemplo, Eprimero se activó, y solo entonces \onese definió, y ahora la definición contiene el código de cat. 13E que se expande a 1.
Sin embargo, pasaré por alto este hecho y reordenaré las definiciones para que tengan un orden lógico (pero que no funcione). En los siguientes párrafos se puede asumir que las letras B, C, D, y Eson activos.
\gdef\S#1{\iftrueBH#1 Q }
(observe que había un pequeño error en la versión anterior, no contenía el espacio final en la definición anterior. Solo lo noté mientras escribía esto. Siga leyendo y verá por qué necesitamos ese para terminar correctamente la macro. )
En primer lugar se define la macro-nivel de usuario, \S. Este no debe ser un personaje activo para tener una sintaxis amigable (?), Por lo que la macro para gwappins eht setterl es \S. La macro comienza con un condicional siempre verdadero \iftrue(pronto quedará claro por qué), y luego llama a la Bmacro seguida de H(que definimos anteriormente como \fi) para que coincida con \iftrue. Luego dejamos el argumento de la macro #1seguido de un espacio y el quark Q. Supongamos que usamos \S{hello world}, luego el flujo de entradadebería verse así: \iftrue BHhello world Q␣(Reemplacé el último espacio por un␣para que la representación del sitio no lo coma, como hice en la versión anterior del código). \iftruees cierto, entonces se expande y nos quedamos BHhello world Q␣. TeX no no retire la \fi( H) después de evaluar el condicional, en cambio, deja allí hasta que el \fiestá realmente expandieron. Ahora la Bmacro se expande:
ABBH#1 {HI#1FC#1|BH}
Bes una macro delimitada cuyo texto de parámetro es H#1␣, por lo que el argumento es lo que sea que esté entre Hy un espacio. Continuando con el ejemplo anterior a la secuencia de entrada antes de la expansión de Bis BHhello world Q␣. Bes seguido por H, como debería (de lo contrario, TeX generaría un error), entonces el siguiente espacio está entre helloy world, también lo #1es la palabra hello. Y aquí tenemos que dividir el texto de entrada en los espacios. Yay: D La expansión de Bquita todo hasta el primer espacio de la corriente de entrada y la sustituye por HI#1FC#1|BHla #1de serhello : HIhelloFChello|BHworld Q␣. Observe que hay un nuevo BHmás adelante en la secuencia de entrada, para hacer una recursión de cola deBy procesar palabras posteriores. Después de que esta palabra se procesa, Bprocesa la siguiente palabra hasta que la palabra a procesar sea el quark Q. Se Qnecesita el último espacio después porque la macro delimitada B requiere uno al final del argumento. Con la versión anterior (ver historial de edición) el código se comportaría mal si lo usara \S{hello world}abc abc(el espacio entre los abcs se desvanecería).
OK, de vuelta a la corriente de entrada: HIhelloFChello|BHworld Q␣. Primero está el H( \fi) que completa la inicial \iftrue. Ahora tenemos esto (pseudocodificado):
I
hello
F
Chello|B
H
world Q␣
El I...F...Hpensar es en realidad una \ifx Q...\else...\fiestructura. La \ifxprueba verifica si la (primera señal de) la palabra tomada es el Qquark. Si es que no hay nada más que hacer y las termina la ejecución, de lo contrario lo que queda es: Chello|BHworld Q␣. Ahora Cse expande:
ACC#1#2|{D#2Q|#1 }
El primer argumento de Cque se no delimitada, por lo menos se preparó será de un solo símbolo, el segundo argumento está delimitado por |, por lo que después de la expansión de C(con #1=hy #2=ello) del flujo de entrada es: DelloQ|h BHworld Q␣. Observe que |se coloca otro , y el hde hellose pone después de eso. La mitad del intercambio está hecho; La primera letra está al final. En TeX es fácil tomar el primer token de una lista de tokens. Una macro simple \def\first#1#2|{#1}obtiene la primera letra cuando la usa \first hello|. El último es un problema porque TeX siempre toma la lista de tokens "más pequeña, posiblemente vacía" como argumento, por lo que necesitamos algunas soluciones. El siguiente elemento en la lista de tokens es D:
ADD#1#2|{I#1FE{}#1#2|H}
Esta Dmacro es una de las soluciones y es útil en el único caso donde la palabra tiene una sola letra. Supongamos que en lugar de hellotener x. En este caso el flujo de entrada sería DQ|x, entonces Dse ampliaría (con #1=Q, y #2vaciar) a: IQFE{}Q|Hx. Esto es similar al bloque I...F...H( \ifx Q...\else...\fi) B, que verá que el argumento es el quark e interrumpirá la ejecución dejando solo la xcomposición tipográfica. En otros casos (volviendo al helloejemplo), Dse expandiría (con #1=ey #2=lloQ) a: IeFE{}elloQ|Hh BHworld Q␣. Una vez más, la I...F...Hcomprobará si hay Qpero se producirá un error y tomar la \elserama: E{}elloQ|Hh BHworld Q␣. Ahora la última pieza de esta cosa, elE la macro se expandiría:
AEE#1#2#3|{I#3#2#1FE{#1#2}#3|H}
El texto del parámetro aquí es bastante similar a Cy D; los argumentos primero y segundo no están delimitados, y el último está delimitado por |. El aspecto de flujo de entrada como esta: E{}elloQ|Hh BHworld Q␣, a continuación, Ese expande (con #1vacío, #2=ey #3=lloQ): IlloQeFE{e}lloQ|HHh BHworld Q␣. Otro de I...F...Hlos controles de bloque para el quark (que ve ly regresa false): E{e}lloQ|HHh BHworld Q␣. Ahora Ese expande de nuevo (con #1=evacío, #2=ly #3=loQ): IloQleFE{el}loQ|HHHh BHworld Q␣. Y otra vez I...F...H. La macro hace algunas iteraciones más hasta Qque finalmente se encuentra y truese toma la rama: E{el}loQ|HHHh BHworld Q␣-> IoQlelFE{ell}oQ|HHHHh BHworld Q␣-> E{ell}oQ|HHHHh BHworld Q␣-> IQoellFE{ello}Q|HHHHHh BHworld Q␣. Ahora el quark se encuentra y se expande condicionales a: oellHHHHh BHworld Q␣. Uf.
Oh, espera, ¿qué son estos? CARTAS NORMALES? ¡Oh chico! Las letras son finalmente encontraron y Tex escribe oell, entonces un montón de H( \fi) se encuentran y se expande (o nada) que sale de la corriente de entrada con: oellh BHworld Q␣. Ahora la primera palabra tiene la primera y la última letra intercambiadas y lo que TeX encuentra a continuación es la otra Bpara repetir todo el proceso para la siguiente palabra.
}
Finalmente terminamos el grupo que comenzó allí para que se deshagan todas las tareas locales. Las tareas locales son los cambios catcode de las letras A, B, C, ... que se hicieron las macros para que vuelvan a su significado normal letra y pueden ser utilizados con seguridad en el texto. Y eso es. Ahora la \Smacro definida allí activará el procesamiento del texto como se indicó anteriormente.
Una cosa interesante sobre este código es que es completamente expandible. Es decir, puede usarlo de manera segura para mover argumentos sin preocuparse de que explote. Incluso puede usar el código para verificar si la última letra de una palabra es la misma que la segunda (por cualquier razón que lo necesite) en una \ifprueba:
\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
Perdón por la explicación (probablemente demasiado) prolija. Traté de hacerlo lo más claro posible para los que no son TeXies también :)
Resumen para los impacientes
La macro \Santepone la entrada con un carácter activo Bque toma listas de tokens delimitados por un espacio final y los pasa a C. Ctoma el primer token en esa lista y lo mueve al final de la lista de tokens y se expande Dcon lo que queda. Dcomprueba si "lo que queda" está vacío, en cuyo caso se encontró una palabra de una sola letra, luego no hace nada; de lo contrario se expande E. Erecorre la lista de tokens hasta que encuentra la última letra de la palabra, cuando se encuentra, deja esa última letra, seguida de la mitad de la palabra, que luego es seguida por la primera letra que queda al final del flujo de tokens C.
Hello, world!se convierte,elloH !orldw(intercambiando la puntuación como una letra) ooellH, dorlw!(manteniendo la puntuación en su lugar)?