在以下 MWE 中,我尝试捕获\at
拆分输入参数的特定字符串(在此字符串中)。我想使用解析器来允许\at
参数中不存在的情况,但不允许出现两次或多次\at
。
\documentclass{article}
\makeatletter
\long\def\@split#1\at#2\@endsplit{#1 -- #2}
\long\def\split#1{\@split#1\@endsplit}
\makeatother
\begin{document}
\split{Hello \at \[ A \] \paragraph{Testing}
\textit{worlds}
Working!
}
% This is also OK
\split{\split{ Hello \at another} \at \split{ something \at World}}
% % How to allow this form producing "Hello ???" for example
% \split{Hello}
% % and issue error for this one
% \split{Hello \at another \at World}
\end{document}
我无法找到一种不定义的方法,\at
这在我的例子中是有问题的,因为我认为我必须在一个组中进行嵌套\split
,但我需要避免创建多余的组。我也可以测试参数是否为空,但参数不能像上一个示例那样长(我认为)。
答案1
您可以使用xparse
的参数处理器来管理您的请求:
\documentclass{article}
\NewDocumentCommand{\printsplit}{ +m +m }{%
#1%
\IfValueT{#2}{~--~#2}}
\NewDocumentCommand{\split}{ > {\SplitArgument{1}{\at}} +m }{%
\printsplit #1}
\begin{document}
\split{Hello \at \[ A \] \paragraph{Testing}
\textit{worlds}
Working!
}
% This is also OK
\split{\split{ Hello \at another} \at \split{ something \at World}}
\split{Hello}
%% and issue error for this one
%\split{Hello \at another \at World}
\end{document}
> {\SplitArgument{1}{\at}} +m
允许“长” m
andatory 参数(带有agraph)最多\par
拆分一次。因此,您可能希望没有拆分,或者只有一个拆分。在前一种情况下,传递给的第二个参数将是可以使用条件测试的。\at
1
\printsplit
-NoValue-
\IfValueT{#2}
答案2
在 处拆分你的参数\at
。这只会\at
在外层找到,因此\split
可以嵌套。
这个名字\split
选得不好,因为amsmath
如果你定义了它,你就不能加载它。或者如果你加载了它,你就不能定义它amsmath
。但对于这个例子来说,这是可以的。
\documentclass{article}
\ExplSyntaxOn
\NewDocumentCommand{\split}{+m}
{
\tohiko_split:n { #1 }
}
\seq_new:N \l__tohiko_split_seq
\cs_new_protected:Nn \tohiko_split:n
{
\seq_set_split:Nnn \l__tohiko_split_seq { \at } { #1 }
\int_case:nnF { \seq_count:N \l__tohiko_split_seq }
{
{0}{--}
{1}{\seq_item:Nn \l__tohiko_split_seq { 1 } ~ -- ~ ??}
{2}{\seq_item:Nn \l__tohiko_split_seq { 1 } ~ -- ~ \seq_item:Nn \l__tohiko_split_seq { 2 }}
}
{\msg_error:nn { tohiko/split } { too-many-at }}
}
\msg_new:nnnn { tohiko/split } { too-many-at }
{Too~many~\token_to_str:N \at\space tokens}
{You~have~too~many~\token_to_str:N \at\space in~the~argument~to~split}
\ExplSyntaxOff
\begin{document}
\split{Hello \at \[ A \] \paragraph{Testing}
\textit{worlds}
Working!
}
% This is also OK
\split{\split{ Hello \at another} \at \split{ something \at World}}
% % How to allow this form producing "Hello ???" for example
\split{Hello}
% % and issue error for this one
\split{Hello \at another \at World}
\end{document}
控制台输出:
This is pdfTeX, Version 3.141592653-2.6-1.40.24 (TeX Live 2022) (preloaded format=pdflatex)
restricted \write18 enabled.
entering extended mode
(./splitat.tex
LaTeX2e <2022-11-01> patch level 1
L3 programming layer <2023-02-07>
(/usr/local/texlive/2022/texmf-dist/tex/latex/base/article.cls
Document Class: article 2022/07/02 v1.4n Standard LaTeX document class
(/usr/local/texlive/2022/texmf-dist/tex/latex/base/size10.clo))
(/usr/local/texlive/2022/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def)
(./splitat.aux)
! Package tohiko/split Error: Too many \at tokens
For immediate help type H <return>.
...
l.46 \split{Hello \at another \at World}
? h
You have too many \at in the argument to split
?
[1{/usr/local/texlive/2022/texmf-var/fonts/map/pdftex/updmap/pdftex.map}]
(./splitat.aux) )</usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfont
s/cm/cmbx10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts
/cm/cmmi10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/
cm/cmr10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm
/cmti10.pfb>
Output written on splitat.pdf (1 page, 43559 bytes).
Transcript written on splitat.log.
答案3
也许这可以实现您想要的功能 — — 而不是\split
命名命令,\SplitAt
以避免与 amsmath-stuff 发生名称冲突:
\errorcontextlines=10000
\makeatletter
%%=============================================================================
%% PARAPHERNALIA:
%% \UD@firstoftwo, \UD@secondoftwo, \UD@stopromannumeral, \UD@CheckWhetherNull
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\@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}%
}%
%%=============================================================================
\@ifdefinable\UD@GobbleToSecondAt{\long\def\UD@GobbleToSecondAt#1\at#2\at{}}%
\@ifdefinable\UD@AtSplit{\long\def\UD@AtSplit#1\at{#1 -- }}%
%You might prefer:
%\@ifdefinable\UD@AtSplit{\long\def\UD@AtSplit#1\at{#1-- }}%
\@ifdefinable\SplitAt{%
\DeclareRobustCommand\SplitAt[1]{%
\romannumeral
\expandafter\UD@CheckWhetherNull\expandafter{\UD@GobbleToSecondAt#1\at\at}{\UD@AtSplit\UD@stopromannumeral#1\at???}{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@GobbleToSecondAt#1\at}{\UD@AtSplit\UD@stopromannumeral#1}{%
\UD@stopromannumeral
\GenericError{}{Error: Too many \string\at\space tokens}{You have too many \string\at\space tokens in the argument to split.}{}%
}%
}%
}%
}%
\makeatother
\documentclass{article}
\begin{document}
\SplitAt{Hello \at \[ A \] \paragraph{Testing}
\textit{worlds}
Working!
}
% This is also OK
\SplitAt{\SplitAt{ Hello \at another} \at \SplitAt{ something \at World}}
% % How to allow this form producing "Hello ???" for example
\SplitAt{Hello}
\message{^^J!!! The next error-message is what is wanted: !!!^^J}%
% % and issue error for this one
\SplitAt{Hello \at another \at World}
\end{document}
注意输出的倒数第二行:
您可以看到,每个破折号周围都有两个空格,而不是一个空格,因为该命令既不会删除空格标记,也不会删除要分开的组件周围的花括号,而是\UD@AtSplit
插入围绕破折号的空格标记。
也许您不想在破折号周围插入额外的空格。在这种情况下,请执行以下操作:
\@ifdefinable\UD@AtSplit{\long\def\UD@AtSplit#1\at{#1-- }}%
。