我想定义一个行为类似的宏\ttfamily
,即它应该读取所有内容直到}
(或\endgroup
?)作为参数。
即这个
{\mynewmacro lorem ipsum
dolores
}
应该相当于这个
\mymacro{lorem ipsum
dolores
}
这可能吗?
答案1
该宏\ttfamily
不会读取}
:它是一个声明,设置(本地)当前字体并且其操作持续到当前组结束。
你可以这样做,但从概念上来说这从一开始就是错误的。
\long\def\mymacro#1{--#1--}
\long\def\mynewmacro{\egroup\iftrue\expandafter\mymacro\expandafter{\else}\fi}
\mymacro{lorem ipsum
dolores
}
{\mynewmacro lorem ipsum
dolores
}
\bye
平衡\egroup
初始的{
;然后我们有一个问题,就是让\mymacro
看到一个明确的{
,并摆脱必要的}
(因为\def
不会接受不平衡的标记列表)。\iftrue
测试遵循真正的分支;实际上它所做的只是消失,留下
\expandafter\mymacro\expandafter{\else}\fi
在输入流中,但 TeX 知道它应该忽略该\else
部分。\expandafter
我们得到了这个\else
,它的扩展删除了直到的所有内容\fi
。所以最后我们剩下
\mymacro{\fi
因此,按照一般规则,\mymacro
将读取匹配的}
。其余部分\fi
将扩展,不留任何内容。
但请注意,你不能将其称为\begingroup\mynewmacro ...\endgroup
也不使用\bgroup
和\egroup
。
答案2
使用以下示例
该宏
\FetchTillCloseBrace{\macro}
获取所有内容直到下一个不匹配的右括号,并将其作为未限定的参数传递给 \macro,重新插入该不匹配的右括号。该宏
\CopyBehindCloseBrace
是一个示例,说明如何从一对括号内放置/复制标记,从而在该范围的结束括号后面形成一个本地范围。
请注意,通过宏/宏参数进行处理会破坏依赖于在不同 catcode-régime 下读取和标记事物的事物,例如,\verb
等等。
\documentclass{article}
\makeatletter
%%----------------------------------------------------------------------
%% 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]{%
\romannumeral0\expandafter\@secondoftwo\string{\expandafter
\@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
\@secondoftwo\string}\expandafter\expandafter\@firstoftwo{ }{}%
\@secondoftwo}{\expandafter\expandafter\@firstoftwo{ }{}\@firstoftwo}%
}%
%%----------------------------------------------------------------------
%% \UD@PullOutFirstUndelimitedArgument{<action>}%
%% {{<e_k>}{<e_(k+1)>}..{<e_n>}}%
%% yields
%% <action>{<e_k>}{{<e_(k+1)>}..{<e_n>}}
%% It must be ensured that list is not empty!
%%......................................................................
\newcommand\UD@Exchange[2]{#2#1}%
\newcommand\UD@KeepFirstTillSelDOM{}%
\long\def\UD@KeepFirstTillSelDOM#1#2\UD@SelDOM{{#1}}%
\newcommand\UD@PullOutFirstUndelimitedArgument[2]{%
\expandafter\UD@Exchange
\expandafter{%
\expandafter{%
\@firstoftwo{}#2}}{\UD@ExtractFirstListElementLoop{#2\UD@SelDOM}{#1}}%
}%
\newcommand\UD@ExtractFirstListElementLoop[1]{%
\expandafter\UD@CheckWhetherNull\expandafter{\@firstoftwo{}#1}%
{\UD@Exchange{#1}}%
{%
\expandafter\UD@ExtractFirstListElementLoop
\expandafter{%
\UD@KeepFirstTillSelDOM#1}%
}%
}%
%%----------------------------------------------------------------------
%% \CopyBehindCloseBrace
%%
%% {<token sequence A>\CopyBehindCloseBrace{<tokens to appear only behind closing brace}<tokens to be copied behind closing brace>}
%% yields:
%% {<token sequence A><tokens to be copied behind closing brace>}<tokens to appear only behind closing brace>{<tokens to be copied behind closing brace>}
%%......................................................................
\newcommand\FetchTillCloseBraceStart[2]{%
\expandafter\expandafter\expandafter\UD@PullOutFirstUndelimitedArgument
\expandafter\expandafter\expandafter#1%
\expandafter\expandafter\expandafter{%
\expandafter\@secondoftwo\string}{}%
{#2}%
}%
\newcommand\CopyBehindCloseBrace{%
\romannumeral0%
\FetchTillCloseBraceStart{\@CopyBehindCloseBrace}%
}%
\newcommand\@CopyBehindCloseBrace[2]{%
\expandafter\@secondoftwo\string{{ }#2}#1{#2}%
}%
%%----------------------------------------------------------------------
%% \FetchTillCloseBrace{\macro}
%%
%% {<token sequence A>\FetchTillCloseBrace{\macro}<remaining tokens in brace group>}
%% yields:
%% {<token sequence A>\macro{<remaining tokens in brace group>}}
%%......................................................................
\newcommand\FetchTillCloseBrace{%
\romannumeral0%
\FetchTillCloseBraceStart{\@PassToMacroInsideScope}%
}%
\newcommand\@PassToMacroInsideScope[2]{%
\expandafter\@secondoftwo\string{{ }#1{#2}}%
}%
%%----------------------------------------------------------------------
%%
%% {ABC \LowercaseTillCloseBrace DEF}
%% -> {ABC \lowercase{DEF}}
%%
%%......................................................................
\newcommand\LowercaseTillCloseBrace{%
\FetchTillCloseBrace{\lowercase}%
}%
\makeatother
\begin{document}
\frenchspacing
{This is rmfamily. \FetchTillCloseBrace{\textsf}This is sffamily.}
This is rmfamily.
\bigskip
{ABC \LowercaseTillCloseBrace DEF}
GHI
\bigskip
{%<--This starts the boldface-group
\bfseries This is boldface.
\CopyBehindCloseBrace{This is to appear only outside the boldface-group. \textit}%
This is to be copied outside the boldface-group.
}%<--This ends the boldface-group
\bigskip
\def\tempa{This is tempa outside the local scope. }%
{%
\def\tempa{This is tempa inside the local scope. }%
\CopyBehindCloseBrace{}\tempa
}
% This does _not(!) work:
% {Text\CopyBehindCloseBrace{Bla}\verb$verbatim text?$}
%
% Nor does this work:
%
% {Text \FetchTillCloseBrace{\textbf}\verb&verbatim \TeX t&}
%
% While this works:
% {Text \bfseries\selectfont \verb&verbatim \TeX t&}
\end{document}