Gibt es eine Möglichkeit, das eigentliche Zeichentoken aus seiner Zeichencodedarstellung abzurufen? Insbesondere hätte ich gern ein Makro, \prepend#1#2
das eine Tokenliste nimmt #1
und das dem Zeichencode entsprechende Zeichentoken voranstellt #2
.
Hier ist eine kurze Demonstration des gewünschten Ergebnisses:
\newtoks\test
\test={bc}
\prepend\test{97}
\showthe\test % should print abc
Antwort1
Sie können Folgendes verwenden \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
Die Terminalausgabe lautet:
> abc.
l.16 \showthe\test
% should print abc
?
> \test=macro:
->abc.
l.21 \show\test
% should print abc again
?
Wie \char_generate:nn
die Zeichen generiert werden, hängt von der verwendeten Engine ab. In LuaTeX wird verwendet tex.cprint(<catcode>, utf8_char(<charcode>))
, ähnlich wie in Henris Antwort, aber mit einer möglichen <catcode>
Einstellung. In XeTeX wird verwendet \Ucharcat <charcode> <catcode>
.
expl3
In den anderen von ( pdftex
, ε-pTeX
, und ) unterstützten Engines ε-upTeX
gibt es keine Möglichkeit,generierenZeichen in Nur-Erweiterungskontexten (ein Hauptmerkmal von \char_generate:nn
), expl3
generiert diese Zeichen also mit dem gleichen Ansatz wie in der Antwort von egreg vorab und \char_generate:nn
verwendet die Zeichen dann einfach, wenn sie angefordert werden.
Wie in egregs Antwort können Sie für einige Catcodes – nämlich 0, 5, 9, 14 und 15 – keine Zeichen generieren, da diese keine Tokens erzeugen (sie verschwinden, wenn TeX die Eingabe scannt, sodass sie auf der Makroerweiterungsebene nicht existieren). Außerdem expl3
erlaubt die Implementierung nicht die Generierung von Leerzeichen aus Gründen der Konsistenz zwischen den Engines, da die Lua-Version dies nicht zulässt. Da Sie jedoch eine Knuth TeX-Version möchten, sind auch Leerzeichen zulässig.
Der folgende Code ist eine Anpassung des expl3
Codes für , der \char_generate:nn
so geändert wurde, dass er in Knuth TeX funktioniert. Der Code ist im Grunde derselbe, außer dass ein paar weitere Komplikationen erforderlich sind, hauptsächlich aufgrund des Fehlens von \unexpanded
, das Ihnen ermöglicht, einzelne Parameter-Token in einem Makro zu haben, und Ihnen ermöglicht, einfach Dinge an ein Makro anzuhängen, ohne dass ein toks-Register erforderlich ist. Abgesehen davon ist es dasselbe.
Der Code definiert zunächst ein temporäres Token-Register, das das Nullzeichen ( ^^@
) mit den verschiedenen möglichen Catcodes enthält, getrennt durch \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
dann durchläuft es alle 256
Zeichencodes und setzt den Wert \lccode
des Nullzeichens auf #1
und verwendet dann den \lowercase
Trick in der Antwort von egreg:
\begingroup
\lccode0=#1
\lccode32=#1
\edef\x{\endgroup
\gdef\expandafter\noexpand
\csname c__char_\romannumeral#1_tl\endcsname{\the\tmptoks}}%
\lowercase\expandafter{\x}
was für einen Zeichencode, sagen wir 97, zu folgendem Ergebnis führt:
\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}
Wenn Ihnen dann ein Zeichencode vorliegt, <charcode>
können Sie mit auf diese Tokenliste zugreifen \csname c__char_\romannumeral<charcode>_tl\endcsname
und erhalten dann mit `\ifcase\fi das angeforderte Zeichen.
Das \chargenerate
Makro prüft zunächst (in \generateaux
), ob die Argumente in einem gültigen Bereich liegen (Catcode zwischen 1 und 13, außer 5 und 9, und Charcode zwischen 0 und 255, obwohl Sie das bei Knuth TeX möglicherweise auf 127 ändern müssen), und ruft dann \generateauxi
mit den Argumenten auf, das dann den \ifcase
obigen Test (mit ein paar weiteren Kleinigkeiten zur Erweiterungskontrolle) verwendet, um das angeforderte Zeichen zu hinterlassen.
Wenn ich den folgenden Code ausführe, tex
erhalte ich:
% 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
Antwort2
\lowercase
ist eine gute Möglichkeit, dies mit jedem TeX zu tun.
\def\prepend#1#2{% toks, charcode
\begingroup
\lccode`9=#2\relax
\lowercase{%
\edef\0{\endgroup
#1={9\the#1}}%
\0}}
Nimmt an, dass das Token-Register nicht ist \0
.
Antwort3
\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
Sie können keine Zeichen mit den Kategoriecodes 0, 1, 2, 5, 9, 14 oder 15 hinzufügen.
Wie Sie sehen, habe ich dem Kategoriecode 3 ein „seltsames“ Zeichen vorangestellt und der Code \the\test$
druckt eine mathematische Formel.
Einschränkung: #1
kann nicht sein \toks0
.
Antwort4
Sie können LuaTeX und die string.char
Funktion verwenden, um einen ASCII-Code in das entsprechende Zeichen umzuwandeln.
\newtoks\test
\test={bc}
\tokspre\test\expandafter{\directlua{tex.sprint(string.char(97))}}
\showthe\test
\bye