试图理解 \@cdr...\@nil 与 \expandafter 的关系

试图理解 \@cdr...\@nil 与 \expandafter 的关系

我正在尝试定义一个\@ifnextchars带有三个参数的宏,第一个参数是字符列表,根据第一个参数的字符是否跟在命令后面,该宏将扩展为第二个或第三个参数。下面是我所做的以及我想如何使用它的一个简单示例。

\documentclass{article}

\makeatletter
\newcommand\@ifnextchars[3]{%
    \expandafter\ifx\expandafter\@empty#1\@empty%
        \def\@ifnextchars@tmp{#3}%
    \else%
        \def\@ifnextchars@tmp{%
            \expandafter\expandafter\expandafter\@ifnextchars@aux\expandafter%
                {\@car#1\@nil}{\@cdr#1\@nil}{#2}{#3}%
        }%
    \fi%
    \@ifnextchars@tmp%
}
\newcommand\@ifnextchars@aux[4]{%
    \expandafter\@ifnextchar#1{%
        #3%
    }{%
        \@ifnextchars{#2}{#3}{#4}%
    }%
}

\newcommand\whereinsentence{%
    \@ifnextchars{.!?}{%
        I am in the end of a sentence.
    }{%
        I am not in the end of a sentence.
    }%
}
\newcommand\vowel{%
    \@ifnextchars{aeiouy}{%
        Vowel:
    }{%
        Not vowel:
    }%
}
\makeatother

\begin{document}

Here is \whereinsentence a sentence\whereinsentence.

\vowel a.

\vowel b.

\end{document}

不幸的是,它不能编译:

Runaway argument?
{I am in the end of a sentence. }{\@ifnextchars {\@cdr \@cdr .!?\@nil \ETC.
! Paragraph ended before \@cdr was complete.
<to be read again> 
                   \par 
l.44 

我猜是它\@cdr在需要时没有扩展。我觉得这很奇怪,因为我确保\@cdr用…扩展了我的\expandafter……所以我猜我不太明白它是如何\expandafter工作的 ☹ 有人能帮我吗?

我受到了这篇文章的启发:概括 \@ifnextchar 以考虑多个字符。 但是,最后这篇帖子是关于创建查找整个单词的变体\@ifnextchar。我只是想知道给定的字符之一是否直接出现。

我已经这样做了,以确保不会与发生反应。我觉得这不太令人满意:如果有人有更好的解决方案,我很乐意接受\ifx\def\@ifnextchar\fi

提前致谢。

答案1

您不能像这样扩展第二个参数。这里有一个借助 eTeX 的简单方法:

\documentclass{article}

\makeatletter
\newcommand\@ifnextchars[3]{%
  \if\relax\detokenize{#1}\relax
    \def\@ifnextchars@tmp{#3}%
  \else
    \edef\@ifnextchars@tmp{%
      \noexpand\@ifnextchars@aux
        {\unexpanded\expandafter{\@car#1\@nil}}
        {\unexpanded\expandafter{\@cdr#1\@nil}}
        \unexpanded{{#2}{#3}}%
    }%
  \fi
  \@ifnextchars@tmp
}
\newcommand\@ifnextchars@aux[4]{%
  \@ifnextchar{#1}{%
    #3%
  }{%
    \@ifnextchars{#2}{#3}{#4}%
  }%
}

\newcommand\whereinsentence{%
  \@ifnextchars{.!?}{%
    I am in the end of a sentence.
  }{%
    I am not in the end of a sentence.
  }%
}
\newcommand\vowel{%
  \@ifnextchars{aeiouy}{%
    Vowel:
  }{%
    Not vowel:
  }%
}
\makeatother

\begin{document}

Here is \whereinsentence a sentence\whereinsentence.

\vowel a.

\vowel b.

\end{document}

答案2

主要问题是您正在扩展\@car,但没有扩展\@cdr,因为 s 链\expandafter未到达它。

expl3这是一个您可能喜欢学习的实现。

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\cs_new_protected:Nn \bodin_ifnext_chars:nnnn
 {
  \tl_if_in:nnTF { #1 } { #2 } { #3 } { #4 } #2
 }

\NewDocumentCommand{\ifnextchars}{mmmm}
 {
  \bodin_ifnext_chars:nnnn { #1 } { #4 } { #2 } { #3 }
 }
\ExplSyntaxOff

\newcommand\whereinsentence{%
    \ifnextchars{.!?}{%
        ``I am in the end of a sentence.''
    }{%
        ``I am not in the end of a sentence.''
    }%
}
\newcommand\vowel{%
    \ifnextchars{aeiouy}{%
        Vowel:
    }{%
        Not vowel:
    }%
}

\begin{document}

Here is \whereinsentence a sentence\whereinsentence.

\vowel a.

\vowel b.

\end{document}

相关内容