Nuestros mejores programadores han agotado sus depósitos de café, buscando día y noche por la resolución, hasta que Perla halló el resultado en GitLab así que hoy la comparte contigo.
Solución:
Normalmente, los nombres de las secuencias de control se componen únicamente de letras o de uno carácter no alfabético.
Una letra es, más precisamente, un carácter que tiene el código de categoría 11 en el momento en que se lee el nombre de la secuencia de control. Por lo tanto, cualquier carácter puede convertirse en parte de un nombre de secuencia de control, siempre que cambiemos su catcode antes de la definición y cada uso.
Con csname...endcsname
nos liberamos de esta limitación y cada personaje puede entrar en ellos para formar un nombre de secuencia de control (por supuesto, %
se excluye porque desaparece junto con lo que queda en la línea antes de que TeX haga su trabajo en los caracteres).
Sin embargo, este no es el objetivo principal de csname...endcsname
. Esta construcción se utiliza para construir comandos a partir de “partes variables”. Piense, por ejemplo, en LaTeX newcounter
: después newcounterfoo
, TeX sabe thefoo
que se construye precisamente de esta manera. Aproximadamente, lo que hace LaTeX es
newcommandnewcounter[1]%
expandafternewcountcsname [email protected]#1endcsname
expandafterdefcsname the#1endcsnamearabic#1%
así que eso newcounterfoo
hace el trabajo correcto. Es más complicado que esto, por supuesto, pero lo principal está aquí; newcount
es el comando de bajo nivel para asignar un contador. los expandafter
es solo construir la secuencia de control antes newcount
y def
ver la ficha.
Dentro csname...endcsname
, los códigos de categoría no importan (con una excepción principal: caracteres activos voluntad ser expandido si no está precedido por string
, ver nota final). LaTeX aprovecha esto para crear nombres de secuencia de control a los que los usuarios no podrán acceder (fácilmente). Por ejemplo, la secuencia de control para elegir la fuente de diez puntos predeterminada es OT1/cmr/m/n/10
, que se puede dividir fácilmente internamente (mediante la operación “inversa” que es string
) y no está disponible para el usuario ocasional.
Otro uso importante es en entornos: cuando dices newenvironmentfoo
, LaTeX realmente define foo
y endfoo
. Al encontrar beginfoo
, LaTeX hace un poco de contabilidad y luego ejecuta csname fooendcsname
(por eso se puede decir también newenvironmentfoo*
); de manera similar, en endfoo
LaTeX se ejecuta csname endfooendcsname
y después de esto vuelve a hacer un poco de contabilidad.
Otros usos: labelfoo
definirá secuencias de control basadas en foo
vía csname...endcsname
que puede ser utilizado por ref
.
Cuando uno dice csname fooendcsname
, LaTeX buscará si foo
se define; si no, se ejecutará relax
y a partir de entonces (respetando la agrupación), foo
será interpretado como relax
. Un uso interesante de esta función es que se puede decir
chapter*Introduction
csname phantomsectionendcsname
addcontentslinetocchapterIntroduction
y mantener hyperref
feliz si está cargado, sin hacer nada si el paquete no está cargado.
Es posible darle muchos otros usos interesantes a este truco. Pero siempre hay que tener en cuenta que TeX no expansión completa de lo que encuentra en ese contexto y que solo personajes debe permanecer. Entonces
csname abcrelax defendcsname
está prohibido. Pero después defxyzabc
,
csname xyz defendcsname
será legal y equivalente a decir csname abcdefendcsname
o abcdef
.
Nota final
Es mejor agregar algo sobre los códigos de categoría. Un personaje activo en csname...endcsname
se expandirá, por lo que para obtener un literal ~
uno tiene que escribir string~
. Los caracteres de comentario (categoría 14), ignorados (categoría 9) e inválidos (categoría 15) seguirán siendo tales. Entonces
csname %endcsname
dará un error (Falta endcsname
); en csname ^^@endcsname
Habrá no personaje y csname ^^?endcsname
generará un error.
Como referencia, del Libro TeX (con ligeros cambios de formato), Capítulo 7: Cómo lee TeX lo que escribe (pág.40):
… puedes pasar de una lista de tokens de caracteres a una secuencia de control diciendo
csname
. Los tokens que aparecen en esta construcción entreendcsname csname
yendcsname
puede incluir otras secuencias de control, siempre que esas secuencias de control finalmente se expandan en caracteres en lugar de primitivas TeX; los caracteres finales pueden ser de cualquier categoría, no necesariamente letras. Por ejemplo,csname
es esencialmente lo mismo que
TeXendcsnameTeX
; pero
csnameTeXendcsname
es ilegal, porqueTeX
se expande en tokens que contienen elkern
primitivo. Es más,
csnamestringTeXendcsname
producirá la secuencia de control inusual\TeX
, es decir, la ficha, que normalmente no se puede escribir.
He usado esto indirectamente usando el label
–ref
sistema y definición de etiquetas basadas en contadores:
newcountermycount
%...
newcommandmycmd%
stepcountermycount%
labelabcthemycount%
%...
Esto crea una “etiqueta sucesiva abc1
, abc2
, … por cada llamada a mycmd
, para evitar crear etiquetas definidas de forma múltiple con el mismo nombre. Indirectamente, labelabcthemycount
llamadas @namedef[email protected]themycount
, que llama
expandafterdefcsname [email protected]themycountendcsname
expandiendo así [email protected]themycount
para [email protected]
y definiendo [email protected]
para la primera etiqueta, [email protected]
para la segunda etiqueta, etc. Sí, las etiquetas en LaTeX son en realidad secuencias de control precedidas por [email protected]
y se construye usando csname ... endcsname
que luego permite numerales.
Suponga que quiere definir un comando foo2
. No puede hacer esto porque 2 no es una letra. Sin embargo, esta construcción funciona: csname foo2endcsname
. A veces esto es útil, por ejemplo, cuando necesita una serie de comandos, foo1
, foo2
, etc. (otra forma es usar números romanos). Otro ejemplo, suponga que desea definir una serie de comandos como endsection
, endsubsection
, etc. Entonces puedes usar un bucle con expandafterdefcsname end#1endcsname...
valoraciones y comentarios
Si te ha resultado de ayuda nuestro post, sería de mucha ayuda si lo compartieras con otros entusiastas de la programación de este modo contrubuyes a extender nuestro contenido.