如果 def 无法解析参数,是否回退?

如果 def 无法解析参数,是否回退?

我喜欢可以(滥用)使用来非常有效地解析字符串的方式\def(另一种选择是循环遍历 LaTeX3 样式的所有字符或使用 LaTeX3 正则表达式,但它更慢,而且通常更难编写)。

如果我们考虑这个 MWE:

\documentclass[]{article}

\begin{document}

\def\firstTry#1MYSEP#2ENDOFLINE{
  The first try succeeded, I want to extract ``#2''.
}

\def\secondTry#1ENDOFLINE{
  The second try succeeded, I want to extract ``#1''.
}

\firstTry foo MYSEPHere is the line I want to extractENDOFLINE

%\firstTry This line has no separator, yet I want to run secondTry on itENDOFLINE

\end{document}

您可以看到第一行将被正确解析\firstTry。是的,第二行注释没有分隔符,因此会产生错误。但是,我还想能够对其进行一些操作(\secondTry在其上运行),而不输出错误消息。在 TeX 中是否可以“尝试”解析,如果解析失败,则使用另一种机制?

答案1

使用适当的分隔宏

\documentclass{article}

\def\firstTry#1EOL{\firstTryA#1SEPSEPEOL}
\def\firstTryA#1SEP#2SEP#3EOL{%
   I want to extract ``\ifx&#2&#1\else#2\fi''%
}

\begin{document}

\firstTry foo SEPHere is the line I want to extractEOL

\firstTry Here is the line I want to extractEOL

\end{document}

在此处输入图片描述

答案2

怎么样:

\documentclass{article}

\newcommand\UDfirstoftwo[2]{#1}
\newcommand\UDsecondoftwo[2]{#2}

\csname @ifdefinable\endcsname{\firstTry}{%
  \long\def\firstTry#1EOL{\firstTryA#1SEPSEPEOL{#1}}%
}%
\csname @ifdefinable\endcsname{\firstTryA}{%
  \long\def\firstTryA#1SEP#2SEP#3EOL#4{%
     % #3 either is empty or is the delimiter "SEP".
     \ifx\relax#3\relax\expandafter\UDfirstoftwo\else\expandafter\UDsecondoftwo\fi
     {\secondTry#4EOL}%
     {The first try succeeded, I want to extract ``\detokenize{#2}''.}%
  }%
}%
\csname @ifdefinable\endcsname{\secondTry}{%
  \long\def\secondTry#1EOL{%
    The second try succeeded, I want to extract ``\detokenize{#1}''.%
  }%
}%

\begin{document}

\ttfamily

\firstTry foo SEPHere is the line I want to extractEOL

\firstTry Here is the line I want to extractEOL

\noindent \fbox{!!! There is brace stripping:}

\firstTry{ foo }SEP{Here is the line I want to extract}EOL

\firstTry{Here is the line I want to extract}EOL

\end{document}

在此处输入图片描述


当将事物作为分隔参数进行处理时,可能会丢失围绕整个参数的花括号对。

因此,如果需要保留括号,事情可能会变得更加棘手;也许我们不应该将事情视为“后备”,而应该将其视为“解析和分叉”:

\documentclass{article}

\newcommand\UDfirstoftwo[2]{#1}%
\newcommand\UDsecondoftwo[2]{#2}%
\newcommand\UDgobble[1]{}%
\csname @ifdefinable\endcsname{\UDgobbleToSEP}{%
  \long\def\UDgobbleToSEP#1SEP{}%
}%
\csname @ifdefinable\endcsname{\UDstopromannumeral}{%
  \chardef\UDstopromannumeral=`\^^00 %
}%
\newcommand\UDCheckWhetherNull[1]{%
  \romannumeral\expandafter\UDsecondoftwo\string{\expandafter
  \UDsecondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \UDsecondoftwo\string}\expandafter\UDfirstoftwo\expandafter{\expandafter
  \UDsecondoftwo\string}\expandafter\UDstopromannumeral\UDsecondoftwo}{%
  \expandafter\UDstopromannumeral\UDfirstoftwo}%
}%
\newcommand\Try{\TryPreventBraceRemoval{}}%
\csname @ifdefinable\endcsname{\TryPreventBraceRemoval}{%
  \long\def\TryPreventBraceRemoval#1EOL{%
    \expandafter\UDCheckWhetherNull\expandafter{\UDgobbleToSEP#1SEP}{%
       % There is no SEP that is not nested in braces in #1:
       \expandafter\DoMyThingWithArgIfNoSEP\expandafter{\UDgobble#1}%
    }{%
       % There is SEP that is not nested in braces in #1:
       \expandafter\DoMyThingWithArgIfSEP\expandafter{\UDgobbleToSEP#1}%
    }%
  }%
}%
\newcommand\DoMyThingWithArgIfNoSEP[1]{%
  The second try succeeded, I want to extract ``\detokenize{#1}''.%
}%
\newcommand\DoMyThingWithArgIfSEP[1]{%
  The first try succeeded, I want to extract ``\detokenize{#1}''.%
}%

\begin{document}

\ttfamily

\ttfamily

\Try foo SEPHere is the line I want to extractEOL

\Try Here is the line I want to extractEOL

\noindent \fbox{!!! There is no brace stripping:}

\Try{ foo }SEP{Here is the line I want to extract}EOL

\Try{Here is the line I want to extract}EOL

\end{document}

在此处输入图片描述

答案3

可能比较慢,但绝对不会更难写。

\documentclass{article}

\ExplSyntaxOn

\NewDocumentCommand{\firstTry}{}
 {
  \peek_regex_replace_once:nnF
   { ([^\c{par}]*?) MYSEP ([^\c{par}]*?) ENDOFLINE }% search
   { The\ first\ try\ succeeded,\ I\ want\ to\ extract\ \2 }% replace
   { NO~MATCH }
 }

\ExplSyntaxOff

\begin{document}

\firstTry foo MYSEPHere is the line I want to extractENDOFLINE

\firstTry what?

\end{document}

由于搜索的是(几乎)任意标记,我选择取消资格\par(这也会匹配空行)。

在此处输入图片描述

相关内容