查找宏的参数中是否存在符号

查找宏的参数中是否存在符号

我编写了以下代码来验证宏的参数是否是一个或多个字段的列表:

\documentclass{amsart}
\scrollmode
\usepackage{xcolor}
\usepackage{xr-hyper}
\usepackage[unicode]{hyperref}
\hypersetup{colorlinks}
\usepackage{framed}
\usepackage{trace}
%\traceon
%\traceoff

\def\OneTheorem{the theorem }
\def\ManyTheorems{theorems }

\def\LastRef{LastRef}%
\def\PrintTheorem#1{\PrtTheorem#1||LastRef||}%
\def\PrtTheorem#1||#2||{\def\temp{#2}%
\ifx\temp\LastRef%
\OneTheorem
\else%
\ManyTheorems
\fi%
}
\def\Refs#1{\RefList#1||LastRef||}%
\def\TheoremSep{}
\def\RefList#1||{\def\temp{#1}%
\ifx\temp\LastRef%
\else%
\TheoremSep\DoTheoremRef{#1}
\def\TheoremSep{, }
\expandafter\RefList%
\fi%
}
\def\DoTheoremRef#1{\DoRefs#1|:LastTRef|:}%
\def\LastTRef{LastTRef}%
\def\DoRefs#1|:#2|:{\def\tempA{#2}%
\ifx\tempA\LastTRef%
(#1)
\else%
(#1-#2)
\fi%
}
\newenvironment{ProofRefA}[1]{%
{\sc ProofA of \PrintTheorem{#1}
\Refs{#1}
}
}%
{\qed}

\begin{document}
\title{Test File}

\begin{abstract}
\end{abstract}
\maketitle

\begin{ProofRefA}{ab1||ab2|:ab3||ab4||ab5}
\end{ProofRefA}

\begin{ProofRefA}{ab5}
\end{ProofRefA}
\end{document}

该宏\PrintTheorem按我预期的方式工作。但是,它会产生额外的输出。可以选择添加以下行:

\expandafter\RefList%

但是,它将是宏的递归调用\RefList。我将看到几个单词定理的副本,并且宏的输出\Refs将消失。经过一番搜索,我找到了代码:

\documentclass{amsart}
\scrollmode
\usepackage{xcolor}
\usepackage{xr-hyper}
\usepackage[unicode]{hyperref}
\hypersetup{colorlinks}
\usepackage{framed}
\usepackage{trace}
%\traceon
%\traceoff

\def\OneTheorem{the theorem }
\def\ManyTheorems{theorems }

\def\LastRef{LastRef}%
\def\PrintTheorem#1{\PrtTheorem#1||LastRef||}%
\def\PrtTheorem#1||#2||{\def\temp{#2}%
\ifx\temp\LastRef%
\OneTheorem
\else%
\ManyTheorems
\expandafter\PrtTheorem
\fi%
}
\def\DoNothing#1||
{
\ifx\temp\LastRef%
\else%
\expandafter\DoNothing
\fi%
}
\def\Refs#1{\RefList#1||LastRef||}%
\def\TheoremSep{}
\def\RefList#1||{\def\temp{#1}%
\ifx\temp\LastRef%
\else%
\TheoremSep\DoTheoremRef{#1}
\def\TheoremSep{, }
\expandafter\RefList%
\fi%
}
\def\DoTheoremRef#1{\DoRefs#1|:LastTRef|:}%
\def\LastTRef{LastTRef}%
\def\DoRefs#1|:#2|:{\def\tempA{#2}%
\ifx\tempA\LastTRef%
(#1)
\else%
(#1-#2)
\fi%
}
\newenvironment{ProofRefA}[1]{%
{\sc ProofA of \PrintTheorem{#1}
\Refs{#1}
}
}%
{\qed}

\begin{document}
\title{Test File}

\begin{abstract}
\end{abstract}
\maketitle

\begin{ProofRefA}{ab1||ab2|:ab3||ab4||ab5}
\end{ProofRefA}

\begin{ProofRefA}{ab5}
\end{ProofRefA}
\end{document}

它运行得更好,但我仍然没有看到宏的输出\Refs

答案1

我不会用它expl3做这份工作。

\documentclass{amsart}

\def\listTheorems#1{\bgroup\ltheorA#1||||}
\def\ltheorA#1||{\ifx^#1^\egroup
   \else \ltheorS({\ltheorB#1::})\expandafter\ltheorA\fi}
\def\ltheorB#1:{\ifx^#1^\else\ltheorD#1\expandafter\ltheorB\fi}
\def\ltheorS{\def\ltheorS{, }}
\def\ltheorD{\def\ltheorD{--}}

\newenvironment{ProofRefA}[1]{%
{\sc ProofA of {\rm \listTheorems{#1}}
}
}%
{\qed}

\begin{document}
\begin{ProofRefA}{ab1||ab2:ab3||ab4||ab5}
Text text.
\end{ProofRefA}

\begin{ProofRefA}{ab5}
Text text.
\end{ProofRefA}
\end{document}

答案2

我会用它expl3来做这项工作。

\documentclass{amsart}

\ExplSyntaxOn

\NewDocumentEnvironment{ProofRefA}{m}
 {
  \textsc{ProofA~of}~\kleyn_proofref:n { #1 }
 }
 {\qed}

\seq_new:N \l__kleyn_proofref_in_seq
\seq_new:N \l__kleyn_proofref_out_seq
\tl_new:N \l__kleyn_proofref_range_tl

\cs_new_protected:Nn \kleyn_proofref:n
 {
  \seq_set_split:Nnn \l__kleyn_proofref_in_seq { || } { #1 }
  \seq_set_map:NNn \l__kleyn_proofref_out_seq \l__kleyn_proofref_in_seq
   {
    (\str_if_in:nnTF {##1} {:} { \__kleyn_proofref_range:n { ##1 } } { ##1 })
   }
  \seq_use:Nn \l__kleyn_proofref_out_seq { ,~ } 
 }

\cs_new_protected:Nn \__kleyn_proofref_range:n
 {
  \tl_set:Nn \l__kleyn_proofref_range_tl { #1 }
  \tl_replace_once:NVn \l__kleyn_proofref_range_tl \c_colon_str { -- }
  \tl_use:N \l__kleyn_proofref_range_tl
 }
\cs_generate_variant:Nn \tl_replace_once:Nnn { NV }

\ExplSyntaxOff


\begin{document}

\title{Test File}

\begin{abstract}
\end{abstract}
\maketitle

\begin{ProofRefA}{ab1||ab2:ab3||ab4||ab5}
\end{ProofRefA}

\begin{ProofRefA}{ab5}
\end{ProofRefA}
\end{document}

在此处输入图片描述

这个想法是将输入拆分为||,然后在项目周围添加括号,但检查冒号是否在项目内,如果在项目内,则用短划线代替冒号。最后,经过处理的项目以“逗号和空格”分隔输出。

答案3

如果您有宏参数是否为空的测试,那么您可以通过将该分隔符附加到该参数,然后从参数中删除该分隔符第一次出现之前的所有内容,来测试该参数是否包含特定分隔符(未嵌套在括号中)。如果结果为空,则该参数不包含该分隔符。如果不为空,则该参数至少包含一个该分隔符的实例。

例如,空测试可以是:

\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
\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}%
}%

或者

\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
\newcommand\UD@CheckWhetherNull[1]{%
  \romannumeral\ifcat$\detokenize{#1}$%
    \expandafter\expandafter\expandafter\UD@stopromannumeral\expandafter\UD@firstoftwo
  \else
    \expandafter\expandafter\expandafter\UD@stopromannumeral\expandafter\UD@secondoftwo
  \fi
}%

如果你想检查宏参数是否不包含|:(除非嵌套在花括号之间),你可以定义

\newcommand\CheckWhetherNoBarColon[1]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@gobbletobarcolon#1|:}%
}%
\@ifdefinable\UD@gobbletobarcolon{\long\def\UD@gobbletobarcolon#1|:{}}%

并按如下方式使用:

\CheckWhetherNoBarColon{⟨argument to check⟩}%
                       {⟨tokens in case ⟨argument to check⟩ does not contain |: (unless nested between curly braces)⟩}%
                       {⟨tokens in case ⟨argument to check⟩ does contain |: which is not nested between curly braces⟩}%

在您的场景中,嵌套尾递归(在||-delimited 项列表上进行迭代,依次将每个项作为|:-delimited 参数列表)可能会起到作用:

\makeatletter
%%=============================================================================
%% Paraphernalia:
%%    \UD@firstoftwo, \UD@secondoftwo, \UD@Exchange, \UD@PassFirstToSecond,
%%    \UD@stopromannumeral, \UD@CheckWhetherNull, \UD@CheckWhetherBlank, 
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@Exchange[2]{#2#1}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\@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 is blank (empty or only spaces):
%%-----------------------------------------------------------------------------
%% -- Take advantage of the fact that TeX discards space tokens when
%%    "fetching" _un_delimited arguments: --
%% \UD@CheckWhetherBlank{<Argument which is to be checked>}%
%%                      {<Tokens to be delivered in case that
%%                        argument which is to be checked is blank>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked is not blank>}%
\newcommand\UD@CheckWhetherBlank[1]{%
  \romannumeral\expandafter\expandafter\expandafter\UD@secondoftwo
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo#1{}{}}%
}%
%%-----------------------------------------------------------------------------
%% Trim one leading and one trailing space if present.
%%   This is borrrowed from trimspaces.sty v 1.1 2009/09/17 by
%%   Will Robertson/Morten Høgholm.
\begingroup
\catcode`\Q=3
\UD@firstoftwo{%
  \endgroup
  \newcommand\UDtrim@spaces[1]{\romannumeral-`\q\UDtrim@trim@\noexpand#1Q Q}%
  \@ifdefinable\UDtrim@trim@{\long\def\UDtrim@trim@#1 Q{\UDtrim@trim@@#1Q}}%
  \@ifdefinable\UDtrim@trim@@{\long\def\UDtrim@trim@@#1Q#2{#1}}%
}{}%
%%-----------------------------------------------------------------------------
\@ifdefinable\UD@gobbletoBarBar{\long\def\UD@gobbletoBarBar#1||{}}%
\@ifdefinable\UD@keeptoBarBar{\long\def\UD@keeptoBarBar#1||{#1}}%
\@ifdefinable\UD@gobbletoBarColon{\long\def\UD@gobbletoBarColon#1|:{}}%
\@ifdefinable\UD@keeptoBarColon{\long\def\UD@keeptoBarColon#1|:{#1}}%
\begingroup
\def\importfrozenrelax#1{%
  \endgroup
  \@ifdefinable\UD@RemoveFromBarBarTillFrozenrelax{%
    \long\def\UD@RemoveFromBarBarTillFrozenrelax##1||##2#1{{##1}||}%
  }%
  \@ifdefinable\UD@RemoveFromBarColonTillFrozenrelax{%
    \long\def\UD@RemoveFromBarColonTillFrozenrelax##1|:##2#1{{##1}|:}%
  }%
  %% \UD@ExtractFirstDelimitedArg{<gobble-macro>}%
  %%                             {<keep-macro>}%
  %%                             {<remove-till-frozen-relax-mmacro>}%
  %%                             {<delimiter>}%
  %%                             {<list of delimited arguments>}%
  \newcommand\UD@ExtractFirstDelimitedArg[5]{%
    \romannumeral\UD@ExtractFirstDelimitedArgLoop{{{}}##5##4#1}{##1}{##2}{##3}%
  }%
}%
\expandafter\expandafter\expandafter\importfrozenrelax
\expandafter\expandafter\expandafter{\expandafter\expandafter\ifnum0=0\fi}%
%%-----------------------------------------------------------------------------
\newcommand\UD@ExtractFirstDelimitedArgLoop[4]{%
  \expandafter\UD@CheckWhetherNull\expandafter{#2#1}%
  {%
    \expandafter\UD@stopromannumeral
    \expandafter{%
      \romannumeral\expandafter\UD@firstoftwo\expandafter\UD@stopromannumeral#3#1%
    }%
  }%
  {\expandafter\UD@ExtractFirstDelimitedArgLoop\expandafter{#4#1}{#2}{#3}{#4}}%
}%
%%-----------------------------------------------------------------------------
% \UD@barbardelimitedloop{<list gathered so far>}% initialize empty
%                        {<stuff to prepend if loop terminates this time>}% initialize to phrase in case no references are specified
%                        {<separator to prepend in this iteration>}% initialize empty
%                        {<separator to prepend in next iteration>}% initialize to comma
%                        {<stuff to prepend if loop terminates with one element>}% initialize to phrase in case a single reference is specified
%                        {<stuff to prepend if loop terminates with several elements>}% initialize to phrase in case deveral references are specified
%                        {<remaining list>}% initialize to environment's argument
\newcommand\UD@barbardelimitedloop[7]{%
  \UD@CheckWhetherBlank{#7}{#2#1}{%
    \expandafter\UD@CheckWhetherNull\expandafter{\UD@gobbletoBarBar#7||}{%
      \UD@barbardelimitedprepend{#7}{#1}{#2}{#3}{#4}{#5}{#6}{}%
    }{%
      \expandafter\UD@PassFirstToSecond\expandafter{\UD@gobbletoBarBar#7}{%
         \expandafter\expandafter\expandafter\UD@barbardelimitedprepend
         \UD@ExtractFirstDelimitedArg{\UD@gobbletoBarBar}{\UD@keeptoBarBar}{\UD@RemoveFromBarBarTillFrozenrelax}{||}{#7}%
         {#1}{#2}{#3}{#4}{#5}{#6}%
       }%
    }%
  }%
}%
\newcommand\UD@barbardelimitedprepend[8]{%
  % #1 - <item in this iteration>
  % #2 - <list gathered so far>
  % #3 - <stuff to prepend if loop terminates this time>
  % #4 - <separator to prepend in this iteration>
  % #5 - <separator to prepend in next iteration>
  % #6 - <stuff to prepend if loop terminates with one element>
  % #7 - <stuff to prepend if loop terminates with several elements>
  % #8 - <remaining list>
  \UD@CheckWhetherBlank{#1}{%
    \UD@barbardelimitedloop{#2}{#3}{#4}{#5}{#6}%
  }{%
    \UD@barcolondelimitedloop{}%
                             {\UD@nojoinwithbarbardelimitedloop{#2}{#3}{#4}{#5}{#6}}%
                             {}%
                             {--}%
                             {\UD@joinwithbarbardelimitedloop{#2#4}{#6}{#5}{#5}{#7}}%
                             {\UD@joinwithbarbardelimitedloop{#2#4}{#7}{#5}{#5}{#7}}%
                             {#1}%
  }%
  {#7}{#8}%
}%
\newcommand\UD@joinwithbarbardelimitedloop[6]{\UD@barbardelimitedloop{#1(#6)}{#2}{#3}{#4}{#5}}%
\newcommand\UD@nojoinwithbarbardelimitedloop[6]{\UD@barbardelimitedloop{#1}{#2}{#3}{#4}{#5}}%
%%-----------------------------------------------------------------------------
% \UD@barcolondelimitedloop{<list gathered so far>}% initialize empty
%                          {<stuff to prepend if loop terminates this time>}%
%                          {<separator to prepend in this iteration>}% initialize empty
%                          {<separator to prepend in next iteration>}% initialiize to --
%                          {<stuff to prepend if loop terminates with one element>}%
%                          {<stuff to prepend if loop terminates with several elements>}%
%                          {<remaining list>}% initialize to current item of ||-list
\newcommand\UD@barcolondelimitedloop[7]{%
  \UD@CheckWhetherBlank{#7}{#2{#1}}{%
    \expandafter\UD@CheckWhetherNull\expandafter{\UD@gobbletoBarColon#7|:}{%
      \UD@barcolondelimitedprepend{#7}{#1}{#2}{#3}{#4}{#5}{#6}{}%
    }{%
      \expandafter\UD@PassFirstToSecond\expandafter{\UD@gobbletoBarColon#7}{%
         \expandafter\expandafter\expandafter\UD@barcolondelimitedprepend
         \UD@ExtractFirstDelimitedArg{\UD@gobbletoBarColon}{\UD@keeptoBarColon}{\UD@RemoveFromBarColonTillFrozenrelax}{|:}{#7}%
         {#1}{#2}{#3}{#4}{#5}{#6}%
       }%
    }%
  }%
}%
\newcommand\UD@barcolondelimitedprepend[8]{%
  \UD@CheckWhetherBlank{#1}{%
    \UD@barcolondelimitedloop{#2}{#3}{#4}{#5}{#6}{#7}{#8}%
  }{%
    \expandafter\UD@barcolondelimitedloop\expandafter{%
      \romannumeral
      \expandafter\expandafter\expandafter\UD@Exchange
      \expandafter\expandafter\expandafter{\UDtrim@spaces{#1}}{\UD@stopromannumeral#2#4}%
    }{#6}{#5}{#5}{#7}{#7}{#8}%
  }%
}%
%%=============================================================================
\newcommand\PrintTheorem[1]{%
  \UD@barbardelimitedloop{}%
                         {Proof(s) of \UnspecifiedTheorems}%
                         {}%
                         {, }%
                         {Proof of \OneTheorem}%
                         {Proofs of \ManyTheorems}%
                         {#1}%
}%
\makeatother

\documentclass{amsart}

\newcommand*\UnspecifiedTheorems{some unspecified theorem(s) }
\newcommand*\OneTheorem{the theorem }
\newcommand*\ManyTheorems{theorems }

\newenvironment{ProofRefA}[1]{{\sc ProofA/\PrintTheorem{#1}}}{\qed}

\begin{document}

\noindent\verb+\begin{ProofRefA}{ab1||ab2|:ab3||ab4||ab5}\end{ProofRefA}+:\\
\begin{ProofRefA}{ab1||ab2|:ab3||ab4||ab5}\end{ProofRefA}
\par\kern\dp\strutbox\hrule\kern\dp\strutbox

\noindent\verb+\begin{ProofRefA}{ab5}\end{ProofRefA}+:\\
\begin{ProofRefA}{ab5}\end{ProofRefA}
\par\kern\dp\strutbox\hrule\kern\dp\strutbox

\noindent\verb+\begin{ProofRefA}{ ab1 || ab2|:ab3 || ab4 || ab5 }\end{ProofRefA}+:\\
\begin{ProofRefA}{ ab1 || ab2|:ab3 || ab4 || ab5 }\end{ProofRefA}
\par\kern\dp\strutbox\hrule\kern\dp\strutbox

\noindent\verb+\begin{ProofRefA}{  ab2|: || }\end{ProofRefA}+:\\
\begin{ProofRefA}{  ab2|: || }\end{ProofRefA}
\par\kern\dp\strutbox\hrule\kern\dp\strutbox

\noindent\verb+\begin{ProofRefA}{  ab2|:  }\end{ProofRefA}+:\\
\begin{ProofRefA}{  ab2|:  }\end{ProofRefA}
\par\kern\dp\strutbox\hrule\kern\dp\strutbox

\noindent\verb+\begin{ProofRefA}{  ab2 || }\end{ProofRefA}+:\\
\begin{ProofRefA}{  ab2 || }\end{ProofRefA}
\par\kern\dp\strutbox\hrule\kern\dp\strutbox

\noindent\verb+\begin{ProofRefA}{ ab2|:ab3  }\end{ProofRefA}+:\\
\begin{ProofRefA}{ ab2|:ab3  }\end{ProofRefA}
\par\kern\dp\strutbox\hrule\kern\dp\strutbox

\noindent\verb+\begin{ProofRefA}{ |: || || |: || ||  }\end{ProofRefA}+:\\
\begin{ProofRefA}{ |: || || |: || ||  }\end{ProofRefA}
\par\kern\dp\strutbox\hrule\kern\dp\strutbox

\noindent\verb+\begin{ProofRefA}{ ab1 || ab2|:ab3|:ab4 || ab5 || ab6 }\end{ProofRefA}+:\\
\begin{ProofRefA}{ ab1 || ab2|:ab3|:ab4 || ab5 || ab6 }\end{ProofRefA}
\par\kern\dp\strutbox\hrule\kern\dp\strutbox

\noindent\verb+\begin{ProofRefA}{ ab1 || ab2|:ab3 || ab4 |: ab5 || ab6 }\end{ProofRefA}+:\\
\begin{ProofRefA}{ ab1 || ab2|:ab3 || ab4 |: ab5 || ab6 }\end{ProofRefA}

\end{document}

在此处输入图片描述

相关内容