Situación

Situación

Cuando uso el signo de almohadilla/signo de número/signo de almohadilla #dentro de comandos y entornos, esto se refiere a argumentos. Sin embargo, no debería \detokenize{#}hacerlo.NO¿un argumento?

Situación

El signo de libra constituye buenos divisores en los archivos de registro.

Ejemplo

Intente descomentar el segundo \detokenizepara obtener un error.

\documentclass{article}
\usepackage{fontspec}% compile with xelatex
\newenvironment{detokenizetest}[1]
{% firstoftwo
 \detokenize{##############################################################################}%
 %\detokenize{##BEGIN#######################################################################}% uncommenting this causes a compile error
}%
{% secondoftwo
}%
\begin{document}
\null
\end{document}

Salida de error

Este error solo ocurre al descomentar la línea que contiene BEGIN.

! Illegal parameter number in definition of \detokenizetest.
<to be read again>
                   }
l.9 }
     %
?

Respuesta1

Dado que #tiene el código de categoría 6, tiene un significado muy especial en TeX, porque se utiliza para indicar parámetros en definiciones de macros.

Las reglas de TeX dicen que cuando quierasalmacenara #en el texto de reemplazo de una macro, es necesario duplicarlo.

Al procesar el texto de reemplazo para una definición de macro, un single #debe ir seguido de un dígito (1 a 9), que indica un puntero al argumento correspondiente, mientras que ##se almacenará como #. Este es el truco que permite algo como

\def\foo{\def\baz##1{-##1-}}

por lo que el texto de reemplazo de \foois \def\baz#1{-#1-}y una llamada de \foose definirán \bazcomo una macro de argumento único.

La primitiva \detokenizeen el texto de reemplazo hará su trabajo.cuando la macro es llamada y expandida, no en el momento de la definición, a menos que la definición se realice con \edef, que primero realizará una expansión completa antes de almacenar el texto de reemplazo en la memoria.

Tenga en cuenta que cuando lo haga \meaning\foo(asumiendo la definición anterior), se le presentará

macro:->\def \baz ##1{-##1-}

y lo mismo ocurrirá con \detokenizeel que utilice el mismo mecanismo. Así algo así como

\edef\hashmarks{\detokenize{####}}

En realidad verá dos #en el texto de reemplazo, pero el resultado final será cuatro de ellos. El mecanismo estándar durante el procesamiento \edefprimero reducirá a la mitad el número de ellos #y luego \detokenizelos duplicará. En particular, ustedno poderproducir de esta manera un número impar de #.

Si desea producir líneas delimitadoras, es mucho mejor usar un método indirecto, haciendo de antemano la lista de tokens requerida que consta #del código de categoría 12. En el ejemplo utilizo tres de ellos, solo porque es un número impar.

\documentclass{article}

\begingroup\lccode`?=`# \lowercase{\endgroup
  \newcommand{\lineofhashsigns}{???}
}

\newenvironment{delimitedtext}
  {\par\lineofhashsigns\par}
  {\par\lineofhashsigns\par}

\begin{document}

\begin{delimitedtext}
abc
\end{delimitedtext}

\end{document}

ingrese la descripción de la imagen aquí

Una definición diferente para \lineofhashsignseso no requiere \lowercasees cambiando el código de categoría:

\catcode`#=12
\newcommand{\lineofhashsigns}{###}
\catcode`#=6

Puedes agregar cualquier token en el texto de reemplazo, siempre y cuando no quieras que la macro tenga argumentos.

Respuesta2

De hecho, la \detokenizeprimitiva significará que #no se trata como un parámetro, sino como uno cuando se expande. Recuerde que en una asignación normal ( \newcommanden LaTeX, \defcomo primitiva TeX) no se produce ninguna expansión. Aquí, \newenvironmentse realiza exactamente lo mismo "solo almacenar" los tokens que \newcommand. Esto significa que tenemos la regla TeX habitual de que al crear una macro, debemos tener los parámetros coincidentes para cada #presente o debemos #duplicar los tokens.

Como \newenvironmentfinalmente se resuelve en a \def, podemos hacer lo que queramos usando \edef:

\edef\detokenizetest#1{%
 \detokenize{##############################################################################}%
 \detokenize{##BEGIN#######################################################################}%
}
\def\enddetokenizetest{}% As \newenvironment will do this
\show\detokenizetest

información relacionada