¿Qué es la "notación #"? ¿Cómo funciona la sintaxis #?

¿Qué es la "notación #"? ¿Cómo funciona la sintaxis #?

Estrechamente relacionada:¿Cómo implementar \expandbefore, de manera similar a \expandafter?

En la pregunta relacionada, se hace referencia a "# Notation". ¿Cómo funciona la sintaxis?

De una respuesta a la otra pregunta:

\makeatletter
%
\newcommand\name{}%
\long\def\name#1#{\UD@innername{#1}}%
%
\newcommand\UD@innername[2]{%
  \expandafter\UD@exchange\expandafter{\csname#2\endcsname}{#1}%
}%
%
\newcommand\UD@exchange[2]{#2#1}%
%
\makeatother

¿Cómo funciona realmente la sintaxis del parámetro (sin número)? \def\test#1#{\csname prueba#1\endcsname}? ¿Cuáles son buenos casos de uso para utilizar este patrón?

Respuesta1

La esencia de \namees:

Con

\name⟨stuff without braces before the left-brace⟩{⟨stuff within braces⟩}

TeX deberá, como primer argumento, buscar ⟨stuff without braces before the left-brace⟩y como segundo argumento procesar ⟨stuff within braces⟩:

Se ⟨stuff within braces⟩toma como el nombre de un token de secuencia de control que se puede obtener envolviendo ⟨stuff within braces⟩y \csname..\endcsnameejecutando la \csname..\endcsnameexpresión resultante.

En lugar de ese token de secuencia de control estará detrás .{⟨stuff within braces⟩}⟨stuff without braces before the left-brace⟩


Cuando se ejecutan macros con argumentos delimitados, (La)TeX reúne los tokens que forman los argumentos del token-stream y, por lo tanto, en el token-stream busca los delimitadores de argumentos, ya que los delimitadores de argumentos se toman como marcadores para finalizar el proceso de reuniendo fichas para el argumento en cuestión.

Los delimitadores que se van a buscar deben indicarse en el⟨texto de parámetro⟩de la definición.

Puede indicar que (La)TeX buscará como delimitador el último argumento, por ejemplo, a \relaxescribiendo \relaxcomo último elemento del⟨texto de parámetro⟩.

Puede indicar que, como delimitador del último argumento, (La)TeX buscará una llave izquierda escribiendo #como último elemento del⟨texto de parámetro⟩.

En (casi ;-) ) cualquier caso el⟨texto de parámetro⟩de una macrodefinición es seguida por la⟨texto de reemplazo⟩, anidado entre llaves.
Así, en (casi ;-) ) cualquier caso el⟨texto de parámetro⟩de una macrodefinición irá seguida por la llave izquierda del par de llaves que rodea la⟨texto de reemplazo⟩.
Así, cuando la última muestra del⟨texto de parámetro⟩es un #, será seguido por un {.
Es por eso que esto para indicar que (La)TeX buscará una llave izquierda como delimitador al recopilar el último argumento para la macro, también se llama #{notación -.

La sutil diferencia con la búsqueda \relaxy la búsqueda de una llave de apertura es:

Cuando (La)TeX como delimitador de un argumento de una macro, por ejemplo, busca \relaxy lo encuentra, no sólo deja de reunir tokens para el argumento, sino que también elimina el delimitador/el \relaxtoken.

Cuando (La)TeX como delimitador para el último argumento de una macro busca la llave izquierda y la encuentra, deja de reunir tokens para el último argumento y deja ese delimitador/esa llave en su lugar y coloca la llave de la macro.⟨texto de reemplazo⟩antes de eso.


Citas del TeXbook del Prof. Donald Ervin Knuth, Capítulo 20: Definiciones (también llamadas Macros) — Prof. Donald Ervin Knuth,profesor emérito del arte de la programación informática en la Universidad de Stanford, es el inventor de TeX:

Ahora que hemos visto varios ejemplos, veamos las reglas precisas que gobiernan las macros TeX. Las definiciones tienen la forma general.

\def⟨secuencia de control⟩⟨texto de parámetro⟩{⟨texto de reemplazo⟩}

donde el⟨texto de parámetro⟩no contiene llaves, y donde todas las apariciones de{y }en el⟨texto de reemplazo⟩están correctamente anidados. Además, el símbolo # tiene un significado especial: en el ⟨texto de parámetro⟩, la primera aparición de # debe ir seguida de 1, la siguiente de 2, y así sucesivamente; se permiten hasta nueve números. En el⟨texto de reemplazo⟩ cada # debe ir seguido de un dígito que apareció después de # en el⟨texto de parámetro⟩, o de lo contrario el # debería ir seguido de otro #. El último caso representa un único token # cuando se expande la macro; el primer caso implica la inserción del argumento correspondiente.

[...]

Se permite una extensión especial a estas reglas: si el último carácter de la⟨texto de parámetro⟩es #, de modo que este # va seguido inmediatamente de {, TeX se comportará como si el{se había insertado en el extremo derecho tanto del texto del parámetro como del texto de reemplazo. Por ejemplo, si dices
'\def\a#1#{\hbox al #1}'
, el texto posterior '\a3pt{x}' se expandirá a '\hbox to 3pt{x}', porque el argumento de \a está delimitado por una llave izquierda.

En otras palabras:

Si dice , el texto posterior se procesará de la siguiente manera:\def\a#1#{\hbox to #1}\a3pt{x}

Como argumento para la macro, \aTeX recopilará del texto siguiente un argumento delimitado por una llave izquierda: recopilará la frase 3pt.
La llave izquierda (y todo lo que hay detrás de ella) se dejará en su lugar mientras se reemplaza \ay su argumento por el⟨texto de reemplazo⟩produce: \hbox to 3ptde modo que todo será: \hbox to 3pt{x}.


En resumen: #{notación - (¡tenga en cuenta la llave izquierda!) significa que el último parámetro de la macro en cuestión está delimitado por una llave izquierda (de código de categoría 1 (comenzar grupo)) que se dejará en su lugar cuando (La) TeX recopila del token-stream el último argumento para esa macro.

El hecho de que en este caso especial el delimitador, es decir, la llave izquierda, se dejará en su lugar es digno de mención, ya que esta es la única situación en la que un delimitador de argumento no se eliminará del flujo de tokens durante el proceso de recopilación de un argumento. .

Es decir, si el delimitador de argumento fuera, por ejemplo, un \relaxtoken como en

\def\mymacro#1\relax{The Argument#1 was delimited by relax. }

, el \relax-token que sirve como delimitador se eliminaría al recopilar el argumento del token-stream: Con

\mymacro , which is nonsense,\relax...

como argumento para \mymacro(La)TeX reuniría del flujo de tokens la secuencia , which is nonsense,y luego encontraría el token \relaxy tomaría ese \relax-token como delimitador del argumento y, por lo tanto, (La)TeX dejaría de reunir tokens para el argumento y eliminaría el delimitador. (Entonces comenzaría a reunir los demás argumentos de \mymacrosi según el⟨texto de parámetro⟩de su definición los había. Pero no hay ninguno.) Entonces entregaría el⟨texto de reemplazo⟩:

The Argument, which is nonsense, was delimited by relax. 

Este⟨texto de reemplazo⟩en el flujo de tokens estaría seguido por los tres puntos y, por lo tanto, ahora el flujo de tokens contendría:

The Argument, which is nonsense, was delimited by relax. ...

Pero si la definición es:

\def\mymacro#1#{The Argument#1 was delimited by a left-brace. }

y dices

\mymacro , which is nonsense,{...

, conseguirás

The Argument, which is nonsense, was delimited by a left-brace. {...

porque a diferencia del caso anterior, donde \relaxse elimina lo que delimita el argumento, en este caso, la llave izquierda que delimita el argumento no se eliminará.


La frase

Si el último personaje del⟨texto de parámetro⟩es #, de modo que este # va seguido inmediatamente de {, TeX se comportará como si el{se había insertado en el extremo derecho tanto del texto del parámetro como del texto de reemplazo.

medio:

Una definición suele ser de patrón.

\def⟨secuencia de control⟩⟨texto de parámetro⟩{⟨texto de reemplazo⟩}

Supongamos que desea definir una macro \macroque procese dos argumentos, el primero de los cuales no está delimitado y el segundo argumento está delimitado por la secuencia \foo\bary que simplemente "escupe" los argumentos.

En este caso creas una expresión como:

\def\macro#1#2\foo\bar{argument 1: #1 argument 2: #2}

⟨secuencia de control⟩=\macro

⟨texto de parámetro⟩=#1#2\foo\bar

⟨texto de reemplazo⟩=argument 1: #1 argument 2: #2

Cuando miras la expresión, ves queen el extremo derecho del⟨texto de parámetro⟩, estarán los tokens que forman el delimitador del último argumento., es decir, los tokens \foo\bar. Pertenecen a las fichas que forman el⟨texto de parámetro⟩. Justo detrás de ellos puedes ver la llave izquierda de ese par de llaves que rodea el⟨texto de reemplazo⟩.
Así, en este caso, en el extremo derecho de la⟨texto de parámetro⟩encuentras los tokens que delimitan el último argumento y encuentras la llave izquierda del par de llaves que rodea el⟨texto de reemplazo⟩.

La secuencia

\macro{A}B\foo\bar

rendimientos:

argument 1: A argument 2: B

Como puede ver, los tokens delimitadores \foo\barse eliminaron mientras se recopilaban los tokens que pertenecen a los argumentos.

Si en cambio defines:

\def\macro#1#2\foo\bar{argument 1: #1 argument 2: #2\foo\bar}

⟨secuencia de control⟩=\macro

⟨texto de parámetro⟩=#1#2\foo\bar

⟨texto de reemplazo⟩=argument 1: #1 argument 2: #2\foo\bar

,es decir, si inserta el delimitador \foo\baren el extremo derecho del⟨texto de reemplazo⟩también, la secuencia

\macro{A}B\foo\bar

rendimientos

argument 1: A argument 2: B\foo\bar

como si con la definición anterior se hubiera dejado el delimitador en su lugar.

¿Qué sucede si desea definir algo así pero el delimitador no es una secuencia \foo\barsino una llave izquierda?

La definición aún debería ser de patrón.

\def\macro#1#2⟨delimiter⟩{argument 1: #1 argument 2: #2⟨delimiter⟩}

pero por varias razones no puedes tomarlo {como⟨delimitador⟩y escribe

\def\macro#1#2{{argument 1: #1 argument 2: #2{}

y por la presente toma #1#2{por el⟨texto de parámetro⟩y argument 1: #1 argument 2: #2{para el⟨texto de reemplazo⟩:

  1. En muchas situaciones, no es fácil insertar llaves izquierdas individuales sin obtener errores debido a que las llaves están desequilibradas.

  2. La situación sería ambigua porque (La)TeX tendría que adivinar si una llave de apertura cerca/en el extremo derecho de la⟨texto de parámetro⟩es un delimitador de argumento o si pertenece a ese par de llaves que rodea el⟨texto de reemplazo⟩.
    (La)TeX también tendría que adivinar si la llave derecha debería coincidir con la llave izquierda al final de la⟨texto de reemplazo⟩o si debería denotar el final del⟨texto de reemplazo⟩.

Por lo tanto, como solución sintáctica, #{se inventó la notación:

Con

\def\macro#1#2#{argument 1: #1 argument 2: #2}

⟨secuencia de control⟩= \macro.

⟨texto de parámetro⟩=#1#2#

⟨texto de reemplazo⟩=argument 1: #1 argument 2: #2

, el⟨texto de parámetro⟩no termina con un token {que delimitará el último argumento pero sí termina con #.

Esto #se usa para indicar que (La)TeX buscará una llave izquierda como delimitador de argumento cuando, durante el proceso de expansión, \macrorecopile los tokens del último argumento \macrodel flujo de tokens. Eso #también denota que la llave izquierda que se encuentra como delimitador se dejará en su lugar para que el⟨texto de reemplazo⟩de \macrova delante de él.

En otras palabras:

Eso #hace que (La)TeX se comporte como si fuera el último token que delimita el último argumento: se encontró una llave izquierda en el⟨texto de parámetro⟩.

También hace que (La)TeX se comporte como si el último token dado en la definición⟨texto de reemplazo⟩era un aparato ortopédico izquierdo.


A tu comentario:

Mmm. ¿Supongo que no podrías inventar algo? ¿Una mejor suposición de lo que está pasando? Permítanme reformular, en su otro ejemplo, si incluso tienen caracteres del código cat 1 flotando en todo esto. ¿Es correcto inferir que este "comportamiento primitivo" ocurre durante la fase de entrada de lectura del archivo? (Lo siento, estoy inventando terminología a medida que avanzo... estoy hablando del process_input_buffercontrolador de eventos.

La primera etapa del procesamiento en LaTeX es leer la entrada (desde el archivo o desde la consola) y tomarla como un conjunto de instrucciones para ponerfichasen el flujo de tokens. (Fichas-de-personaje/fichas-de-secuencia-de-control). En etapas posteriores, se procesan los tokens del flujo de tokens. En una de estas etapas anteriores, se expanden los tokens expandibles, por ejemplo, macros. Es decir, son reemplazados por aquellos tokens que forman los textos de reemplazo de sus definiciones. En esta etapa tiene lugar la recopilación de tokens para macroargumentos. Por lo tanto, el comportamiento no tiene lugar al leer el archivo, sino después de leerlo y tokenizarlo, en la etapa de expansión de tokens expandibles y, por lo tanto, reunir otros.fichascomo sus argumentos.


Intenté explicar en detalle cómo (La)TeX recopila y procesa argumentos macro en mi respuesta a la pregunta.¿Cómo busca TeX argumentos delimitados?

Intenté detallar en detalle \expandafterlas formas de evitarlo en mi respuesta a la pregunta.¿Cómo puedo saber el número de expandafter cuando agrego a una macro csname?

Intenté desarrollar en detalle la macro \nameen mi respuesta a la pregunta.Definir una secuencia de control después de que un espacio importe

información relacionada