传递另一个命令时,命令吞噬额外字母不起作用

传递另一个命令时,命令吞噬额外字母不起作用

另一个话题,我得到了以下命令作为答案:它采用两个字母的字体形状(scit...)或完整版本(scshapeitshape...)来设置相应的字体形状。

\documentclass{article}

\newcommand*\setfontshape[1]{\setfontshapeA #1shape\relax}
\def\setfontshapeA#1shape#2\relax{\csname #1shape\endcsname}

\begin{document}
{\setfontshape{sc} hello}
{\setfontshape{scshape} hello}
\end{document}

问题是,当传递另一个宏时,命令会中断

\documentclass{article}

\newcommand*\setfontshape[1]{\setfontshapeA #1shape\relax}
\def\setfontshapeA#1shape#2\relax{\csname #1shape\endcsname}

\newcommand{\myshapeshort}{sc}
\newcommand{\myshapefull}{scshape}

\begin{document}
{\setfontshape{\myshapeshort} hello}  % Works
{\setfontshape{\myshapefull} hello}   % Does not work
\end{document}

有没有办法使命令更加健壮,并使其在任何情况下都能工作(甚至是命令、调用命令、调用命令……以及递归)?

答案1

问题:-)在于扩展,正如您自己所标记的那样。当您将宏传递给\setfontshape

\setfontshape{\foo}

扩展为

\setfontshapeA\foo shape\relax

\setfontshapeA现在的扩展不是扩展宏\foo本身,但只返回

\csname\foo shape\endcsname

如果\foo仅包含sc则有效,否则无效。

您必须延迟 的扩展\setfontshapeA。只要您传递给 的参数\setfontshape最多只有一个宏,那么一个简单的

\newcommand*\setfontshape[1]{\expandafter\setfontshapeA #1shape\relax}

可能会奏效。但是,如果你编造出像

\def\foo{scsh}
\def\baz{ape}
\setfontshape{\foo\baz}

那么你需要先充分展开论点。你可以这样做

\newcommand*\setfontshape[1]{\expandafter\setfontshapeA\expanded{#1}shape\relax}

或者

\newcommand*\setfontshape[1]{\edef\next{#1shape}\expandafter\setfontshapeA\next\relax}

前者需要相对较新的 pdfTeX(2018),而后者是纯 Knuth-TeX。

答案2

扩展问题。我的解决方案是定义一个合适的变体。

\documentclass{article}
\usepackage{lmodern}

\ExplSyntaxOn

\NewDocumentCommand{\setfontshape}{m}
 {
  \IfBlankF{#1}
   {
    \vincent_shape:e { #1 }
   }
 }

\cs_new_protected:Nn \vincent_shape:n
 {
  \use:c { #1 \int_compare:nT { \str_count:n { #1 } < 5 } { shape } }
 }

\cs_generate_variant:Nn \vincent_shape:n { e }

\ExplSyntaxOff

\newcommand{\myshapeshort}{sc}
\newcommand{\myshapefull}{scshape}

\begin{document}

{\setfontshape{sc}AbcDef}
{\setfontshape{scshape}AbcDef}
{\setfontshape{it}AbcDef}
{\setfontshape{itshape}AbcDef}
{\setfontshape{sl}AbcDef}
{\setfontshape{slshape}AbcDef}
{\setfontshape{sc}\setfontshape{sl}AbcDef}

{\setfontshape{\myshapeshort} hello}  % Works
{\setfontshape{\myshapefull} hello}   % Works

\end{document}

在此处输入图片描述

答案3

如果你喜欢 Knuth-TeX 引擎的代码,你可以嵌套\csname-expansion 以通过 inner 扩展内容,\csname..\endcsname然后再通过 outer 进行字符串化和删除“形状” \csname..\endcsname

\documentclass{article}

\csname @ifdefinable\endcsname\MyRemoveXYAndshapeAndBeyond{%
  \edef\MyRemoveXYAndshapeAndBeyond{%
    \long\def\noexpand\MyRemoveXYAndshapeAndBeyond
    ##1\string X\string Y##2\string s\string
    h\string a\string p\string e##3\relax{##2}%
  }%
  \MyRemoveXYAndshapeAndBeyond
}

\newcommand\setfontshape[1]{%
  \csname
    \expandafter\expandafter
    \expandafter            \MyRemoveXYAndshapeAndBeyond
    \expandafter\string
    \csname XY#1shape\endcsname\relax
    shape%
  \endcsname
}

\newcommand{\myshapeshort}{sc}
\newcommand{\myshapefull}{scshape}

\begin{document}
{\setfontshape{sc} hello}
{\setfontshape{scshape} hello}
{\setfontshape{\myshapeshort} hello}  % Works
{\setfontshape{\myshapefull} hello}   % Works
{\setfontshape{\myshapefull this is a secret message} hello}   % Works
\end{document}

如果正在使用 TeX 引擎\expanded并且\unexpanded可用,并且您希望通过一些卑鄙的用户输入来防止奇怪的“缺少 \endcsname”错误,您可以执行以下操作:

\documentclass{article}

\expanded{%
  \long\def\noexpand\MyRemoveshapeAndBeyond
  #1\string s\string h\string a\string p\string e%
}%
#2\relax{#1}

\newcommand\setfontshape[1]{%
  \csname
    \expandafter\MyRemoveshapeAndBeyond
    \detokenize\expanded{{#1shape}}\relax
    shape%
  \endcsname
}

\newcommand{\myshapeshort}{sc}
\newcommand{\myshapefull}{scshape}

\begin{document}
{\setfontshape{sc} hello}
{\setfontshape{scshape} hello}
{\setfontshape{\myshapeshort} hello}  % Works
{\setfontshape{\myshapefull} hello}   % Works
{\setfontshape{\myshapefull this is a secret message} hello}   % Works
\end{document}

你提出了这个问题:

有没有办法使命令更加健壮,并使其在任何情况下都能工作(甚至是命令、调用命令、调用命令……以及递归)?

调用命令意味着尝试成功执行算法。 在您的情况中,“成功执行算法”在其他事情之下意味着所讨论的算法

  • 只能传递适合形成命令名的标记。此要求意味着算法的执行只能由扩展来驱动。
  • 可能无法终止,因为已经创建了需要中止并提供错误消息或类似信息的情况。
  • 应该在某个时候终止。

我认为很难实现对任意宏参数的检查,即基于宏的机制(最初具有一组特定的宏参数)是否会产生满足这些要求的算法,如果不是,则以某种方式化解/消除这种情况。

相关内容