首先,这个问题不是现实世界的问题,它只是为了看看使用 TeX 是否可以实现以下操作。
考虑这个简短的代码:
\begingroup
\toks0={\def\foo<}
\toks1={>}
\edef\bar{\the\toks0 foo\the\toks1}
\show\bar
\endgroup
<
是否可以分别用显式括号和替换>
上述代码中的{
和}
,以便\bar
扩展为\def\foo{foo}
?
我找到了一种使用两个 s 来获得所需结果的方法\edef
:
\begingroup
\toks0={\noexpand\def\noexpand\foo{\iffalse}\fi}
\toks1={\iffalse{\fi}}
\edef\bar{\the\toks0 foo\the\toks1}
\expandafter\edef\expandafter\bar\expandafter{\bar}
\show\bar
\endgroup
但这要求两个寄存器中的所有标记都为第二个做好准备\edef
。我对一个解决方案感兴趣(如果有的话),该解决方案可以逐字使用两个寄存器的内容。
答案1
鉴于您不能在令牌寄存器中存储不平衡的括号,也许这是一种替代方法......<
在寄存器中存储一个按照您想要的语法运行的活动字符,即:\toks0={\gdef\foo<}
和\toks1={>}
。
激活时,<
表现为\gdef<#1>{{#1}}
。
\documentclass{article}
\def\tmpA#1#2{\expandafter#1\expandafter#2}
\def\tmpB#1{\expandafter\tmpA\the\toks0 #1}
\def\usethetoks#1{\def\tmpC{\tmpB #1}%
\expandafter\tmpC\the\toks1}
\begingroup
\catcode`<=\active
\gdef<#1>{{#1}}
\endgroup
\begin{document}
\begingroup
\catcode`<=\active
\toks0={\gdef\foo<}
\toks1={>}
\usethetoks{bar}
\toks0={\gdef\foobar<Pre-}
\toks1={-post>}
\usethetoks{baz}
\endgroup
\foo{} and \foobar
Is $<$ restored? \ifnum1<2\relax True\else False\fi
\end{document}
答案2
您不能将不平衡的标记列表存储在定义文本中,也不能存储在标记列表寄存器中。
您可以使用特殊令牌来伪造它,在这里\BGROUP
并\EGROUP
在最后进行替换。
\documentclass{article}
\ExplSyntaxOn
\NewDocumentCommand{\splitdefbegin}{mO{0}}
{
\siracusa_splitdef_begin:nn { #1 } { #2 }
}
\NewDocumentCommand{\splitdefadd}{m}
{
\siracusa_splitdef_add:n { #1 }
}
\NewDocumentCommand{\splitdefend}{ }
{
\siracusa_splitdef_end:
}
\tl_new:N \l__siracusa_splitdef_name_tl
\int_new:N \l__siracusa_splitdef_args_int
\prg_generate_conditional_variant:Nnn \regex_match:nn { nV } { T,F,TF }
\cs_generate_variant:Nn \cs_set:Nn { cV }
\cs_new_protected:Nn \siracusa_splitdef_begin:nn
{
\tl_set:Nn \l__siracusa_splitdef_name_tl { #1 }
\int_set:Nn \l__siracusa_splitdef_args_int { #2 }
\tl_build_begin:N \l__siracusa_splitdef_body_tl
}
\cs_new_protected:Nn \siracusa_splitdef_add:n
{
\tl_build_put_right:Nn \l__siracusa_splitdef_body_tl { #1 }
}
\cs_new_protected:Nn \siracusa_splitdef_end:
{
\tl_build_end:N \l__siracusa_splitdef_body_tl
\__siracusa_splitdef_normalize:
\cs_set:cV
{ __siracusa_splitdef_temp:\prg_replicate:nn { \l__siracusa_splitdef_args_int } { n } }
\l__siracusa_splitdef_body_tl
\cs_set_eq:cc
{ \l__siracusa_splitdef_name_tl }
{ __siracusa_splitdef_temp:\prg_replicate:nn { \l__siracusa_splitdef_args_int } { n } }
}
\cs_new_protected:Nn \__siracusa_splitdef_normalize:
{
% recursively replace \BGROUP...\EGROUP with {...}
\regex_match:nVT { \c{BGROUP} } \l__siracusa_splitdef_body_tl
{
\regex_replace_all:nnN
{ \c{BGROUP}(.*)\c{EGROUP} } % search
{ \cB\{ \1 \cE\} } % replace
\l__siracusa_splitdef_body_tl % in
\__siracusa_splitdef_normalize:
}
}
\ExplSyntaxOff
\splitdefbegin{foo}[2]
\splitdefadd{x\fbox\BGROUP#1}
\splitdefadd{y\fbox\BGROUP{#2}z\EGROUP}
\splitdefadd{!\EGROUP}
\splitdefend
\begin{document}
\texttt{\meaning\foo}
\foo{A}{B}
\end{document}