假设我们要处理作为参数给出的标记列表,并且要在\futurelet
处理之前检查每个标记。如何识别\futurelet
空格后的标记?
请考虑以下示例:
\def\process#1{\doA#1}
\def\doA {\show\fl\futurelet\fl\doB}
\def\doB#1{\show\fl\futurelet\fl\doC}
\def\doC {\show\fl}
\process{ ab}
\bye
我们通过命令得到以下输出\show
:
\doA: \fl=undefined % clearly, \fl hasn't yet been defined
\doB: \fl=blank space % \fl has been letted to the blank space
% If it were a normal token, we could consume it with an argument,
% and would have #1=space in \doB and \fl=a in \doC
\doC: \fl=the letter b % However, the space is skipped when parsing the argument,
% so we end up with #1=a in \doB and \fl=b in \doC
\fl=the letter a
那么在能够检测和处理空间之后,我们如何进入这样的状态呢?
相关问题:定义\myspace
使其与 相等\fl
(当 时\fl=blank space
)的最佳方式是什么?通过\ifx
(或任何其他if
)?以下类型的工作(除了虚假空间)。
\def\defmyspace#1{\futurelet\myspace\relax#1}
\defmyspace{ }
\show\myspace % \myspace=blank space
答案1
您可以\process{ ab}
使用\futurelet
以下宏:
\def\process#1{\doA#1\end}
\def\doA{\futurelet\fl\doB}
\def\doB{\ifx\fl\end\else \reportfl \afterassignment\doA \fi \let\next= }
\def\reportfl{\message{\meaning\fl}}
\process{ ab}
\end
我修正了我的代码中的一个错误(Ulrich 和 Donald 的评论)并将报告移到\fl
宏中,以便像 这样的标记\if
也\fi
可以被处理。
答案2
受到 wipet 的回答的启发,我建议使用\let
-\afterassignment
循环:
\def\process#1{\afterassignment\doA\let\next= #1\process\process}
\def\doA{%
\ifx\next\process\else
\message{\meaning\next}%
\afterassignment\doA
\fi
\let\next= %
}
\process{ ab}
\message{done}
\end
(假设 的参数\process
不包含其含义等于 的含义的标记\process
。)
控制台输出为:
This is pdfTeX, Version 3.14159265-2.6-1.40.21 (TeX Live 2020) (preloaded format=pdftex)
restricted \write18 enabled.
entering extended mode
(./test.tex blank space the letter a the letter b done )
No pages of output.
Transcript written on test.log.
对于您的“相关问题”:
代替
\def\defmyspace#1{\futurelet\myspace\relax#1}
\defmyspace{ }
\show\myspace
考虑到它只\let ... = ...
消耗后面一个可选空间=
,并执行以下操作:
\def\myspace#1{#1}
\myspace{\let\myspace= } %
\show\myspace
只要\lccode
空格字符的和字符\lccode
的=
不表明\lowercase
影响这些字符,您也可以执行以下操作:
\lowercase{\let\myspace= } %
\show\myspace
在 LaTeX 2ε 中\@sptoken
可用。
由于 Wipet 已经提供了一个展示用法的出色答案\let
,\futurelet
因此\afterassignment
我决定提供一种完全不同的方法来解决这个问题 — — 如果你真的希望从论证的角度来“看待”事物,这种方法可能很适合。
根据您打算执行的具体操作,您可能可以在没有赋值/没有\futurelet
/ 的情况下进行尾部递归迭代\let
:
%%-----------------------------------------------------------------------------
%% Paraphernalia:
%%.............................................................................
\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
\long\def\exchange#1#2{#2#1}%
\chardef\stopromannumeral=`\^^00%
\secondoftwo{}{\long\def\removespace} {}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\long\def\CheckWhetherNull#1{%
\romannumeral\expandafter\secondoftwo\string{\expandafter
\secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\secondoftwo\string}\expandafter\firstoftwo\expandafter{\expandafter
\secondoftwo\string}\expandafter\stopromannumeral\secondoftwo}%
{\expandafter\stopromannumeral\firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument's first token is an explicit
%% catcode-1-character-token
%%.............................................................................
%% \CheckWhetherBrace{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked has leading
%% explicit catcode-1-character-token>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked does not have a leading
%% explicit catcode-1-character-token>}%
\long\def\CheckWhetherBrace#1{%
\romannumeral\expandafter\secondoftwo\expandafter{\expandafter{%
\string#1.}\expandafter\firstoftwo\expandafter{\expandafter
\secondoftwo\string}\expandafter\stopromannumeral\firstoftwo}%
{\expandafter\stopromannumeral\secondoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether brace-balanced argument starts with a space-token
%%.............................................................................
%% \CheckWhetherLeadingExplicitSpace{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case
%% <argument which is to be checked>
%% does have a leading explicit space-
%% token>}%
%% {<Tokens to be delivered in case
%% <argument which is to be checked>
%% does not have a leading explicit
%% space-token>}%
\long\def\CheckWhetherLeadingExplicitSpace#1{%
\romannumeral\CheckWhetherNull{#1}%
{\expandafter\stopromannumeral\secondoftwo}%
{%
% Let's nest things into \firstoftwo{...}{} to make sure they are nested in braces
% and thus do not disturb when the test is carried out within \halign/\valign:
\expandafter\firstoftwo\expandafter{%
\expandafter\expandafter\expandafter\stopromannumeral
\romannumeral\expandafter\secondoftwo
\string{\CheckWhetherLeadingExplicitSpaceB.#1 }{}%
}{}%
}%
}%
\long\def\CheckWhetherLeadingExplicitSpaceB#1 {%
\expandafter\CheckWhetherNull\expandafter{\firstoftwo{}#1}%
{\exchange{\firstoftwo}}{\exchange{\secondoftwo}}%
{\expandafter\expandafter\expandafter\stopromannumeral
\expandafter\expandafter\expandafter}%
\expandafter\secondoftwo\expandafter{\string}%
}%
%%-----------------------------------------------------------------------------
%% Extract first inner undelimited argument:
%%
%% \romannumeral\ExtractFirstArgLoop{ABCDE\SelDOm} yields A
%%
%% \romannumeral\ExtractFirstArgLoop{{AB}CDE\SelDOm} yields AB
%%
%% \romannumeral\ExtractFirstArgLoop{\SelDOm ABCDE\SelDOm} yields \SelDOm
%%.............................................................................
\long\def\RemoveTillSelDOm#1#2\SelDOm{{#1}}%
\long\def\ExtractFirstArgLoop#1{%
\expandafter\CheckWhetherNull\expandafter{\firstoftwo{}#1}%
{\expandafter\stopromannumeral\secondoftwo{}#1}%
{\expandafter\ExtractFirstArgLoop\expandafter{\RemoveTillSelDOm#1}}%
}%
%%-----------------------------------------------------------------------------
%%
\long\def\process#1{%
\CheckWhetherNull{#1}{}{%
\CheckWhetherLeadingExplicitSpace{#1}{%
The first token of {\tt\string\process} is an explicit space token.\hfill\break
\expandafter\process\expandafter{\removespace#1}%
}{%
\CheckWhetherBrace{#1}{%
The first token of {\tt\string\process} is an opening brace.\hfill\break
\expandafter\process\expandafter{\romannumeral\ExtractFirstArgLoop{#1\SelDOm}}%
The first token of {\tt\string\process} is a closing brace.\hfill\break
}{%
The first token of {\tt\string\process} is: {\tt\expandafter\string\romannumeral\ExtractFirstArgLoop{#1\SelDOm}}\hfill\break
}%
\expandafter\process\expandafter{\firstoftwo{}#1}%
}%
}%
}%
\noindent{\tt\string\noindent}\hfill\break
{\tt\string\process\string{ ab\string{cd\string}e f \string\TeX\string}}
\bigskip
\noindent
\process{ ab{cd}e f \TeX}%
\bye
从您的评论中我了解到该问题与 LaTeX 2ε 中参数的字符串化有关。
请注意,上述方法并不适用于对参数进行正确的字符串化,因为在没有实际检查右括号的情况下就消耗了匹配的花括号。
我可以提供一个字符串化例程来检查左括号和右括号。(除了/之外,可能还有类似/甚至更糟的 / ...){1
}2
X1
Y2
␣1
␣2
%% Copyright (C) 2019, 2020 by Ulrich Diez ([email protected])
%%
%% This work may be distributed and/or modified under the
%% conditions of the LaTeX Project Public Licence (LPPL), either
%% version 1.3 of this license or (at your option) any later
%% version. (The latest version of this license is in:
%% http://www.latex-project.org/lppl.txt
%% and version 1.3 or later is part of all distributions of LaTeX
%% version 1999/12/01 or later.)
%% The author of this work is Ulrich Diez.
%% This work has the LPPL maintenance status 'not maintained'.
%% Usage of any/every component of this work is at your own risk.
%% There is no warranty - neither for probably included
%% documentation nor for any other part/component of this work.
%% If something breaks, you usually may keep the pieces.
\errorcontextlines=10000
\documentclass{article}
\makeatletter
%%=============================================================================
%% Paraphernalia:
%% \UD@firstoftwo, \UD@secondoftwo,
%% \UD@PassFirstToSecond, \UD@Exchange, \UD@removespace
%% \UD@CheckWhetherNull, \UD@CheckWhetherBrace,
%% \UD@CheckWhetherLeadingSpace, \UD@ExtractFirstArg
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\newcommand\UD@Exchange[2]{#2#1}%
\@ifdefinable\UD@removespace{\UD@Exchange{ }{\def\UD@removespace}{}}%
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral\expandafter\UD@secondoftwo\string{\expandafter
\UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\UD@stopromannumeral\UD@secondoftwo}{%
\expandafter\UD@stopromannumeral\UD@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument's first token is a catcode-1-character
%%.............................................................................
%% \UD@CheckWhetherBrace{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked has a leading
%% explicit catcode-1-character-token>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked does not have a
%% leading explicit catcode-1-character-token>}%
\newcommand\UD@CheckWhetherBrace[1]{%
\romannumeral\expandafter\UD@secondoftwo\expandafter{\expandafter{%
\string#1.}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\UD@stopromannumeral\UD@firstoftwo}{%
\expandafter\UD@stopromannumeral\UD@secondoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether brace-balanced argument starts with a space-token
%%.............................................................................
%% \UD@CheckWhetherLeadingSpace{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case <argument
%% which is to be checked> does have a
%% leading explicit space-token>}%
%% {<Tokens to be delivered in case <argument
%% which is to be checked> does not have a
%% a leading explicit space-token>}%
\newcommand\UD@CheckWhetherLeadingExplicitSpace[1]{%
\romannumeral\UD@CheckWhetherNull{#1}%
{\expandafter\UD@stopromannumeral\UD@secondoftwo}%
{%
% Let's nest things into \UD@firstoftwo{...}{} to make sure they are nested in braces
% and thus do not disturb when the test is carried out within \halign/\valign:
\expandafter\UD@firstoftwo\expandafter{%
\expandafter\expandafter\expandafter\UD@stopromannumeral
\romannumeral\expandafter\UD@secondoftwo
\string{\UD@CheckWhetherLeadingExplicitSpaceB.#1 }{}%
}{}%
}%
}%
\@ifdefinable\UD@CheckWhetherLeadingExplicitSpaceB{%
\long\def\UD@CheckWhetherLeadingExplicitSpaceB#1 {%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
{\UD@Exchange{\UD@firstoftwo}}{\UD@Exchange{\UD@secondoftwo}}%
{\expandafter\expandafter\expandafter\UD@stopromannumeral
\expandafter\expandafter\expandafter}%
\expandafter\UD@secondoftwo\expandafter{\string}%
}%
}%
%%-----------------------------------------------------------------------------
%% Extract first inner undelimited argument:
%%
%% \UD@ExtractFirstArg{ABCDE} yields {A}
%%
%% \UD@ExtractFirstArg{{AB}CDE} yields {AB}
%%.............................................................................
\@ifdefinable\UD@RemoveTillUD@SelDOm{%
\long\def\UD@RemoveTillUD@SelDOm#1#2\UD@SelDOm{{#1}}%
}%
\newcommand\UD@ExtractFirstArg[1]{%
\romannumeral\UD@ExtractFirstArgLoop{#1\UD@SelDOm}%
}%
\newcommand\UD@ExtractFirstArgLoop[1]{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
{\UD@stopromannumeral#1}%
{\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillUD@SelDOm#1}}%
}%
%%-----------------------------------------------------------------------------
%% In case an argument's first token is an opening brace, stringify that and
%% add another opening brace before that and remove everything behind the
%% matching closing brace:
%% \UD@StringifyOpeningBrace{{Foo}bar} yields {{Foo} whereby the second
%% opening brace is stringified:
%%.............................................................................
\newcommand\UD@StringifyOpeningBrace[1]{%
\romannumeral
\expandafter\UD@ExtractFirstArgLoop\expandafter{%
\romannumeral\expandafter\expandafter\expandafter\UD@stopromannumeral
\expandafter\expandafter
\expandafter {%
\expandafter\UD@firstoftwo
\expandafter{%
\expandafter}%
\romannumeral\expandafter\expandafter\expandafter\UD@stopromannumeral
\expandafter\string
\expandafter}%
\string#1%
\UD@SelDOm}%
}%
%%-----------------------------------------------------------------------------
%% In case an argument's first token is an opening brace, remove everything till
%% finding the corresponding closing brace. Then stringify that closing brace:
%% \UD@StringifyClosingBrace{{Foo}bar} yields: {}bar} whereby the first closing
%% brace is stringified:
%%.............................................................................
\newcommand\UD@StringifyClosingBrace[1]{%
\romannumeral\expandafter\expandafter\expandafter
\UD@StringifyClosingBraceloop
\UD@ExtractFirstArg{#1}{#1}%
}%
\newcommand\UD@CheckWhetherStringifiedOpenBraceIsSpace[1]{%
%% This can happen when character 32 (space) has catcode 1...
\expandafter\UD@CheckWhetherLeadingExplicitSpace\expandafter{%
\romannumeral\expandafter\expandafter\expandafter\UD@stopromannumeral
\expandafter\UD@secondoftwo
\expandafter{%
\expandafter}%
\expandafter{%
\romannumeral\expandafter\expandafter\expandafter\UD@stopromannumeral
\expandafter\UD@firstoftwo
\expandafter{%
\expandafter}%
\romannumeral\expandafter\expandafter\expandafter\UD@stopromannumeral
\expandafter\string
\expandafter}%
\string#1%
}%
}%
\newcommand\UD@TerminateStringifyClosingBraceloop[2]{%
\expandafter\expandafter\expandafter\UD@stopromannumeral%
\expandafter\expandafter
\expandafter{%
\expandafter\string
\romannumeral\expandafter\expandafter\expandafter\UD@stopromannumeral
\expandafter#1%
\string#2%
}%
}%
\newcommand\UD@StringifyClosingBraceloopRemoveElement[4]{%
\expandafter\UD@PassFirstToSecond\expandafter{\expandafter
{\romannumeral\expandafter\UD@secondoftwo\string}{}%
\UD@CheckWhetherStringifiedOpenBraceIsSpace{#4}{%
\UD@Exchange{\UD@removespace}%
}{%
\UD@Exchange{\UD@firstoftwo\expandafter{\expandafter}}%
}{%
\expandafter\expandafter\expandafter\UD@stopromannumeral
\expandafter#1%
\romannumeral\expandafter\expandafter\expandafter\UD@stopromannumeral
\expandafter
}%
\string#4%
}{\expandafter\UD@StringifyClosingBraceloop\expandafter{#2#3}}%
}%
\newcommand\UD@StringifyClosingBraceloop[2]{%
\UD@CheckWhetherNull{#1}{%
\UD@CheckWhetherStringifiedOpenBraceIsSpace{#2}{%
\UD@TerminateStringifyClosingBraceloop{\UD@removespace}%
}{%
\UD@TerminateStringifyClosingBraceloop{\UD@firstoftwo\expandafter{\expandafter}}%
}%
{#2}%
}{%
\UD@CheckWhetherLeadingExplicitSpace{#1}{%
\UD@StringifyClosingBraceloopRemoveElement
{\UD@removespace}{\UD@removespace}%
}{%
\UD@StringifyClosingBraceloopRemoveElement
{\UD@firstoftwo\expandafter{\expandafter}}{\UD@firstoftwo{}}%
}%
{#1}{#2}%
}%
}%
%%-----------------------------------------------------------------------------
%% Apply <action> to the stringification of each token of the argument:
%%
%% \StringifyNAct{<action>}{<token 1><token 2>...<token n>}
%%
%% yields: <action>{<stringification of token 1>}%
%% <action>{<stringification of token 2>}%
%% ...
%% <action>{<stringification of token n>}%
%%
%% whereby "stringification of token" means the result of applying \string
%% to the token in question.
%% Due to \romannumeral-expansion the result is delivered after two
%% \expandafter-chains.
%% If you leave <action> empty, you can apply a loop on the list formed by
%% {<stringification of token 1>}%
%% {<stringification of token 2>}%
%% ...
%% {<stringification of token n>}%
%%.............................................................................
\newcommand\StringifyNAct{%
\romannumeral\StringifyNActLoop{}%
}%
%%.............................................................................
%% \StringifyNActLoop{{<stringification of token 1>}...{<stringification of token k-1>}}%
%% {<action>}%
%% {<token k>...<token n>}
%%.............................................................................
\newcommand\StringifyNActLoop[3]{%
\UD@CheckWhetherNull{#3}{%
\UD@stopromannumeral#1%
}{%
\UD@CheckWhetherBrace{#3}{%
\expandafter\expandafter\expandafter\UD@Exchange
\expandafter\expandafter\expandafter{%
\UD@StringifyClosingBrace{#3}%
}{%
\expandafter\StringifyNActLoop\expandafter{%
\romannumeral
\expandafter\expandafter\expandafter\UD@Exchange
\expandafter\expandafter\expandafter{\UD@StringifyOpeningBrace{#3}}{\StringifyNActLoop{#1}{#2}}%
}{#2}%
}%
}{%
\UD@CheckWhetherLeadingExplicitSpace{#3}{%
\expandafter\UD@PassFirstToSecond\expandafter{\UD@removespace#3}{%
\StringifyNActLoop{#1#2{ }}{#2}%
}%
}{%
\expandafter\UD@PassFirstToSecond\expandafter{\UD@firstoftwo{}#3}{%
\expandafter\StringifyNActLoop\expandafter{%
\romannumeral%
\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\UD@PassFirstToSecond
\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter{%
\expandafter\expandafter\expandafter\string
\expandafter\UD@Exchange
\romannumeral\UD@ExtractFirstArgLoop{#3\UD@SelDOm}{}%
}{\UD@stopromannumeral#1#2}%
}%
{#2}%
}%
}%
}%
}%
}%
%%.............................................................................
%% Now a routine which you can apply as <action> within \StringifyNAct:
%%.............................................................................
\newcommand\printstringifiedtoken[1]{%
A token was stringified as
\UD@CheckWhetherLeadingExplicitSpace{#1}{%
\fbox{\texttt{\char`\ \strut}} (explicit space token\strut)%
}{%
\fbox{\texttt{#1\strut}}%
}
.\\
}%
%%.............................................................................
%% Now a routine which you can apply when prefering iterating on the result
%% of \StringifyNAct
%%.............................................................................
\newcommand\printstringifiedtokenloop[1]{%
\ifx\relax#1\expandafter\@gobble\else\expandafter\@firstofone\fi
{\printstringifiedtoken{#1}\printstringifiedtokenloop}%
}%
\makeatother
\pagestyle{empty}
\begin{document}
\vspace*{-4cm}\enlargethispage{4cm}
\begin{verbatim*}
\noindent
\StringifyNAct{\printstringifiedtoken}{%
\textbf{\csname @firstofone\endcsname{\LaTeX} is funny.}
}
\end{verbatim*}
yields:\bigskip
\noindent
\StringifyNAct{\printstringifiedtoken}{%
\textbf{\csname @firstofone\endcsname{\LaTeX} is funny.}
}
(The last explicit space token is due to the \verb|\endlinechar|-thingie
while the state of \LaTeX's reading-apparatus is in state M (middle of line)
after a curly closing brace. It also is in that state after an opening
curly brace.)
\newpage
\vspace*{-4cm}\enlargethispage{4cm}
\begin{verbatim*}
\noindent
\expandafter\expandafter
\expandafter\printstringifiedtokenloop
\StringifyNAct{}{%
\textbf{\csname @firstofone\endcsname{\LaTeX} is funny.}
}%
\relax
\end{verbatim*}
yields:\bigskip
\noindent
\expandafter\expandafter
\expandafter\printstringifiedtokenloop
\StringifyNAct{}{%
\textbf{\csname @firstofone\endcsname{\LaTeX} is funny.}
}%
\relax
(The last explicit space token is due to the \verb|\endlinechar|-thingie
while the state of \LaTeX's reading-apparatus is in state M (middle of line)
after a curly closing brace. It also is in that state after an opening
curly brace.)
\end{document}
答案3
该tokcycle
包设置为循环使用标记。这是最简单的演示,显示您定义了对每个标记要执行的操作...在这里,我将字符括起来,并将空格括起来。
更复杂的指令可以测试标记并根据其 charcode 或 catcode 进行分支。
空间有它们自己的指令,因为 TeX 吸收它们的方式不同,正如您在问题中提到的那样。
我应该指出,使用 tokcycle 的正常方式是,将处理过的标记添加到 toks 寄存器中,然后您可以在最后重新使用它。在这里,由于演示的简单性(例如,标记不会作为参数相互交互),我放弃了它,\cytoks
只是即时处理了标记。
最后,我要指出的是,MWE 使用\tokcyclexpress{...}
带参数的宏形式。该包还提供了伪环境形式\tokencyclexpress...\endtokencyclexpress
。
\documentclass {article}
\usepackage{tokcycle}
\begin{document}
\Characterdirective{[#1]}
\Spacedirective{(#1)}
\tokcyclexpress{ ab}
\end{document}
下面是一个稍微复杂一点的字符指令的例子,其中的a
标记还被设为斜体:
\Characterdirective{[\tctestifx{a#1}{\textit{#1}}{#1}]}
补充
现在,为了好玩,我演示了 tokcycle 如何跟踪标记的主动和隐式性质。请注意,在示例 3 中,a 不是斜体,因为它是由 处理的,它\Macrodirective
是通过\def
而不是定义的\let
。宏指令设置为在括号之间提供标记。
\documentclass {article}
\usepackage{tokcycle}
\begin{document}
\newcommand\checkAI{$\ifimplicittok_\mathrm{implicit}\fi
\ifactivetok^\mathrm{active}\fi$}
\Characterdirective{[\tctestifx{a#1}{\textit{#1}}{#1}]\checkAI}
\Macrodirective{\{#1\}\checkAI}
\Spacedirective{(#1)\checkAI}
1. \tokcyclexpress{ ab}
2.\let\q a
\tokcyclexpress{ \q b}
3.\catcode`Q=\active
\defQ{a}
\tokcyclexpress{ Qb}
4.\letQa
\tokcyclexpress{ Qb}
5. \def\:{\let\z= }\:
\tokcyclexpress{\z Qb}
6. \catcode`Z=\active
\def\:{\let Z= }\:
\tokcyclexpress{ZQb}
7. \tokcyclexpress{\space Qb}
\end{document}