¿Hay alguna forma de obtener el token de carácter real a partir de su representación de código de carácter? En particular, me gustaría tener una macro \prepend#1#2
que tome una lista de tokens y le #1
anteponga el token de carácter correspondiente al código de carácter .#2
Aquí hay una breve demostración del resultado deseado:
\newtoks\test
\test={bc}
\prepend\test{97}
\showthe\test % should print abc
Respuesta1
Puedes usar \char_generate:nn { <charcode> } { <catcode> }
:
\input expl3-generic
\ExplSyntaxOn
\cs_new_eq:NN \toks_use:N \tex_the:D
\cs_new_protected:Npn \prepend #1 #2
{
\if:w \exp_not:N #1 #1
\use:x { #1 = { \char_generate:nn {#2} { 12 } \toks_use:N #1 } }
\else:
\tl_put_left:Nx #1 { \char_generate:nn {#2} { 12 } }
\fi:
}
\ExplSyntaxOff
\newtoks\test
\test={bc}
\prepend\test{97}
\showthe\test % should print abc
\def\test{bc}
\prepend\test{97}
\show\test % should print abc
\bye
La salida del terminal será:
> abc.
l.16 \showthe\test
% should print abc
?
> \test=macro:
->abc.
l.21 \show\test
% should print abc again
?
La forma \char_generate:nn
de generar los caracteres depende del motor que esté en uso. En LuaTeX usa tex.cprint(<catcode>, utf8_char(<charcode>))
, de manera similar a la respuesta de Henri, pero con una posible <catcode>
configuración. En XeTeX se utiliza \Ucharcat <charcode> <catcode>
.
En los otros motores soportados por expl3
( pdftex
, ε-pTeX
y ε-upTeX
) no hay manera de realmentegenerarcaracteres en contextos de solo expansión (una característica clave de \char_generate:nn
), por lo que expl3
genera previamente estos caracteres usando el mismo enfoque que en la respuesta de egreg, y luego \char_generate:nn
simplemente usa los caracteres cuando se le solicita.
Como en la respuesta de egreg, no puedes generar caracteres de algunos códigos cat, es decir, 0, 5, 9, 14 y 15, porque no producen tokens (desaparecen cuando TeX escanea la entrada, por lo que no existen). a nivel de macroexpansión). Además, la expl3
implementación no permite la generación de caracteres de espacio para mantener la coherencia entre motores, porque la versión Lua no lo permite. Sin embargo, como desea una versión de Knuth TeX, también se permiten caracteres de espacio.
El siguiente código es una adaptación del expl3
código \char_generate:nn
modificado para que funcione en Knuth TeX. El código es básicamente el mismo, excepto que se necesitan algunas complicaciones más, principalmente debido a la falta de \unexpanded
, que le permite tener tokens de parámetro único en una macro y le permite agregar cosas fácilmente a una macro sin la necesidad de un toks. registro. Aparte de eso, es lo mismo.
El código primero define un registro toks temporal que contiene el carácter nulo ( ^^@
) con los diferentes catcodes posibles, separados por \or
:
\or ^^@% 1
\or ^^@% 2
\or ^^@% 3
\or ^^@% 4
\or % 5 Invalid
\or ^^@^^@% 6 Has to be doubled for a later `\def`
\or ^^@% 7
\or ^^@% 8
\or % 9 Invalid
\or ^^@% 10
\or ^^@% 11
\or ^^@% 12
\or ^^@% 13
luego recorre todos 256
los códigos de caracteres y establece el \lccode
carácter nulo en #1
y luego usa el \lowercase
truco en la respuesta de egreg:
\begingroup
\lccode0=#1
\lccode32=#1
\edef\x{\endgroup
\gdef\expandafter\noexpand
\csname c__char_\romannumeral#1_tl\endcsname{\the\tmptoks}}%
\lowercase\expandafter{\x}
que para un código de carácter, digamos 97, da como resultado:
\gdef\c__char_xcvii_tl{\or a\or a\or a\or a\or \or aa\or a\or a\or \or a\or a\or a\or a}
luego, dado un código de carácter <charcode>
, puede acceder a esa lista de tokens \csname c__char_\romannumeral<charcode>_tl\endcsname
y luego con `\ifcase\fi tiene el carácter solicitado.
La \chargenerate
macro primero verifica (en \generateaux
) si los argumentos están en un rango válido (catcode entre 1 y 13, excepto 5 y 9, y charcode entre 0 y 255, aunque con Knuth TeX es posible que necesites cambiarlo a 127), y luego llama \generateauxi
con los argumentos, que luego usa la \ifcase
prueba anterior (con algunos fragmentos más para el control de expansión) para dejar el carácter solicitado.
Al ejecutar el siguiente código tex
obtengo:
% Auxiliaries
\long\def\gobbletoqstop#1\qstop{}
\long\def\firstofone#1{#1}
\chardef\expend=0
% Expandable error message
\begingroup
\long\xdef\expandableerror#1{%
\noexpand\expandafter\noexpand\expandafter\noexpand\expandafter
\noexpand\gobbletoqstop\noexpand\firstofone
{\csname Error! \endcsname#1}\noexpand\qstop}
\endgroup
% Append stuff to a toks register
\def\toksputright#1{%
\begingroup
\def\toksputtoks{#1}%
\afterassignment\toksputrightaux
\toks0=}
\def\toksputrightaux{%
\edef\x{\endgroup
\toksputtoks={\the\toksputtoks\the\toks0}}%
\x}
% Set up constant token lists
\newtoks\tmptoks
\begingroup
\tmptoks{ \noexpand\or}%
\catcode0=1
\toksputright\tmptoks{^^@\iffalse}}%
\catcode0=2
\toksputright\tmptoks{{\fi\noexpand\or^^@}%
\begingroup
\def\noop{}%
\edef\x{\expandafter\noop\the\tmptoks}%
\expandafter\endgroup
\expandafter\tmptoks\expandafter{\x}%
\catcode0=3 \toksputright\tmptoks{\or^^@}%
\catcode0=4 \toksputright\tmptoks{\or^^@}%
\catcode0=5 \toksputright\tmptoks{\or}%
\catcode0=6 \toksputright\tmptoks{\or^^@^^@}%
\catcode0=7 \toksputright\tmptoks{\or^^@}%
\catcode0=8 \toksputright\tmptoks{\or^^@}%
\catcode0=9 \toksputright\tmptoks{\or}%
\catcode0=10 \toksputright\tmptoks\expandafter{\firstofone{\or}^^@}%
\catcode0=11 \toksputright\tmptoks{\or ^^@}%
\catcode0=12 \toksputright\tmptoks{\or^^@}%
\catcode0=13 \toksputright\tmptoks{\or^^@}%
\def\chartmp#1;{%
\begingroup
\lccode0=#1
\lccode32=#1
\edef\x{\endgroup
\gdef\expandafter\noexpand
\csname c__chargen_\romannumeral#1_tl\endcsname{\the\tmptoks}}%
\lowercase\expandafter{\x}}%
\let^^L\relax
\catcode`^^L=12
\count0=0
\loop
\expandafter\chartmp\number\count0;
\advance\count0 by 1
\ifnum\count0<256 \repeat
\endgroup
% Main definition
\def\chargenerate#1#2{%
\romannumeral\expandafter\generateaux
\number#1\expandafter;\number#2;}
% Check for invalid input
\def\generateaux#1;#2;{%
\ifnum0%
\ifnum#1=0 1\fi
\ifnum#2=10 1\fi
=11
\expandableerror{Cannot generate null char as a space.}%
\else
\ifodd0%
\ifnum#2< 1 1\fi
\ifnum#2= 5 1\fi
\ifnum#2= 9 1\fi
\ifnum#2>13 1\fi\space
\expandableerror{Invalid catcode for char generation.}%
\else
\ifodd0%
\ifnum#1< 0 1\fi
\ifnum#1>"FF 1\fi\space
\expandableerror{Charcode requested out of engine range.}%
\else
\generateauxi{#1}{#2}%
\fi
\fi
\fi
\expend}
% Actual char generation
\def\generateauxi#1#2#3\expend{%
#3%
\iffalse{\fi
\expandafter\expandafter
\expandafter\expend
\expandafter\expandafter
\ifcase#2%
\csname c__chargen_\romannumeral#1_tl\endcsname
\or}
\fi}
% Testing
\def\empty{}
\begingroup
\lccode`\~=`a
\lowercase{\endgroup
\gdef ~{\ active character a}%
}
\def\test#1{%
\edef\x{%
\ifnum#1=2 {\iffalse}\fi\space\noexpand\meaning\fi % add { if a is a }
\chargenerate{97}{#1}%
\ifnum#1=6 \chargenerate{97}{#1}\fi% add another # if a is a #
\ifnum#1=1 \iffalse{\fi\space\noexpand\meaning}\fi % if a is a {, add a }
}%
\ifx\x\empty
#1: ERROR
\else
#1: \expandafter\meaning\x
\fi\par}
\tt\scrollmode
\count2=0
\loop
\test{\the\count2 }%
\advance\count2 by 1
\ifnum\count2<16
\repeat
\bye
Respuesta2
\lowercase
es una buena manera de hacer esto, con cualquier TeX.
\def\prepend#1#2{% toks, charcode
\begingroup
\lccode`9=#2\relax
\lowercase{%
\edef\0{\endgroup
#1={9\the#1}}%
\0}}
Se supone que el registro de toks no es \0
.
Respuesta3
\newtoks\test
\def\prepend#1#2{%
\ifcase\catcode#2\relax
% 0, do nothing
\or
% 1, do nothing
\or
% 2, do nothing
\or
\prependaux#1{#2}{$}% 3
\or
\prependaux#1{#2}{&}% 4
\or
% 5, do nothing
\or
\prependaux#1{#2}{##}% 6
\or
\prependaux#1{#2}{^}% 7
\or
\prependaux#1{#2}{_}% 8
\or
% 9, do nothing
\or
\prependaux#1{#2}{ }% 10
\or
\prependaux#1{#2}{a}% 11
\or
\prependaux#1{#2}{?}% 12
\or
\prependaux#1{#2}{~}% 13
% 14 or 15, do nothing
\fi
}
\def\prependaux#1#2#3{%
\begingroup\lccode`#3=#2\relax
\lowercase{\endgroup\toks0={#3}}%
#1\expandafter{\the\toks\expandafter0\the#1}%
}
\test={bc}
\prepend\test{97}
\message{\number`?}
\catcode`?=3
\prepend\test{63}
\the\test$
\prepend\test{`\#}
\showthe\test
\bye
No puede agregar caracteres con códigos de categoría 0, 1, 2, 5, 9, 14 o 15.
Como puede ver, antepuse un carácter "extraño" del código de categoría 3 y el código \the\test$
imprime una fórmula matemática.
Restricción: #1
no puede ser \toks0
.
Respuesta4
Puede utilizar LuaTeX y la string.char
función para convertir un código ASCII en el carácter correspondiente.
\newtoks\test
\test={bc}
\tokspre\test\expandafter{\directlua{tex.sprint(string.char(97))}}
\showthe\test
\bye