Anhängen eines Zeichens an eine Tokenliste unter Verwendung seines Zeichencodes

Anhängen eines Zeichens an eine Tokenliste unter Verwendung seines Zeichencodes

Gibt es eine Möglichkeit, das eigentliche Zeichentoken aus seiner Zeichencodedarstellung abzurufen? Insbesondere hätte ich gern ein Makro, \prepend#1#2das eine Tokenliste nimmt #1und 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:nndie 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>.

expl3In den anderen von ( pdftex, ε-pTeX, und ) unterstützten Engines ε-upTeXgibt es keine Möglichkeit,generierenZeichen in Nur-Erweiterungskontexten (ein Hauptmerkmal von \char_generate:nn), expl3generiert diese Zeichen also mit dem gleichen Ansatz wie in der Antwort von egreg vorab und \char_generate:nnverwendet 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 expl3erlaubt 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 expl3Codes für , der \char_generate:nnso 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 256Zeichencodes und setzt den Wert \lccodedes Nullzeichens auf #1und verwendet dann den \lowercaseTrick 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\endcsnameund erhalten dann mit `\ifcase\fi das angeforderte Zeichen.

Das \chargenerateMakro 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 \generateauximit den Argumenten auf, das dann den \ifcaseobigen Test (mit ein paar weiteren Kleinigkeiten zur Erweiterungskontrolle) verwendet, um das angeforderte Zeichen zu hinterlassen.

Wenn ich den folgenden Code ausführe, texerhalte ich:

Bildbeschreibung hier eingeben

% 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

\lowercaseist 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: #1kann nicht sein \toks0.

Antwort4

Sie können LuaTeX und die string.charFunktion 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

verwandte Informationen