可选参数为空或根本没有提供可选参数?

可选参数为空或根本没有提供可选参数?

我了解到\parbox有五个参数,即:\parbox[<align>][<height>][<inner-align>]{<width>}{<text>}。所以我构造了自己的 \myparbox,并在其中添加了\sloppy\setlength\parfillskip{0pt}#5。但它失败了。原因是什么以及如何重新定义 \myparbox?

梅威瑟:

\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand{\myparbox}{ooomm}{%
  \parbox[#1][#2][#3]{#4}{\sloppy\setlength\parfillskip{0pt}#5}
}
\begin{document}
AAA\fbox{\parbox[][][]{4em}{aa bb cc dd ee ff}}AAA\\% parbox typesets nothing. why?
BBB\fbox{\myparbox{4em}{aa bb cc dd ee ff}}BBB% This fails to compile
\end{document}

编辑:

\documentclass{article}
\usepackage{xparse}
\let\oldparbox\parbox
\RenewDocumentCommand{\parbox}{sO{c}oO{t}mm}{%
  \IfBooleanTF{#1}
    {%
      \IfNoValueTF{#3}
        {\oldparbox[#2]{#5}{\sloppy\setlength\parfillskip{0pt}#6}}
        {\oldparbox[#2][#3][#4]{#5}{\sloppy\setlength\parfillskip{0pt}#6}}
    }
    {%
      \IfNoValueTF{#3}
        {\oldparbox[#2]{#5}{#6}}
        {\oldparbox[#2][#3][#4]{#5}{#6}}
    } 
}
\begin{document}\the\fboxsep
AAA\fbox{\parbox[t]{8em}{aa bb cc dd ee ff gg hh ii}}AAA\\% parbox typesets nothing why?.
BBB\fbox{\parbox*{6em}{aa bb cc dd ee ff}}BBB% This fails to compile
\end{document}

答案1

正如注释中所述,空的可选参数[]不一定等同于根本没有提供可选参数。不提供参数是否等同于传递特定值必须通过命令的文档或实现进行检查。

在示例中,情况变得更糟,因为如果没有给出相应的可选参数,则xparse的可选o参数实际上包含特殊标记值。您可以并且应该使用(如建议的那样)测试值的存在性-NoValue-\IfNoValueTF达莱夫的评论)。

当您只有一个可选参数需要处理时,这是一个非常可行的解决方案,但如果参数数量增加,它就会变得混乱。

在这种情况下,\parbox您可以发现默认参数是c\relax作为特殊标记,s当您查找中的定义时sourc2e.pdf

所以你可以尝试

\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand{\myparbox}{O{c}O{\relax}O{s}mm}{%
  \parbox[#1][#2][#3]{#4}{\sloppy\setlength\parfillskip{0pt}#5}%
}
\begin{document}
BBB\fbox{\parbox{4em}{\sloppy\setlength\parfillskip{0pt}aa bb cc dd ee ff}}BBB

BBB\fbox{\myparbox{4em}{aa bb cc dd ee ff}}BBB
\end{document}

通常我会尝试解决此类问题,这些问题需要我知道默认的可选参数值/行为,或者需要大量\IfNoValueTF测试才能获得正确的参数,因为第一种方法看起来很脆弱,第二种方法非常冗长和重复。类似于Marijn 的回答可能是一种替代方案,但至少在这种情况下还需要对 的定义为有深入的了解\parbox


编辑:我刚刚才看到问题的新版本。\let对于具有可选参数的强大命令来说是不够的:何时使用 \LetLtxMacro?。我还强烈建议不要重新定义基本命令,即使\parbox实现可能向后兼容。新名称更安全。

答案2

或者,您可以使用xpatch在命令中的正确位置插入额外代码,而无需传递变量。该\parbox命令调用处理实际内容的内部\@iiiparbox命令,因此这个内部命令是应该修补的命令。MWE:

\documentclass{article}
\usepackage{xpatch}
\begin{document}
\makeatletter
\xpatchcmd{\@iiiparbox}{#5}{\sloppy\setlength\parfillskip{0pt}#5}{}{}
\makeatother
AAA\fbox{\parbox{4em}{aa bb cc dd ee ff}}AAA
\end{document}

请注意,这会改变所有 parbox 的行为。如果您想要一个具有对齐对齐的自定义命令,同时保留常规命令,那么您可以使用命令的副本定义自定义命令\@iiiparbox,然后修补副本而不是原始命令。MWE:

\documentclass{article}
\usepackage{xpatch}
\begin{document}
\makeatletter
\def\myparbox{\@ifnextchar [\@iparbox {\myiiiparbox c\relax [s]}}
\let\myiiiparbox\@iiiparbox
\xpatchcmd{\myiiiparbox}{#5}{\sloppy\setlength\parfillskip{0pt}#5}{}{} 
\makeatother
AAA\fbox{\parbox{4em}{aa bb cc dd ee ff}}AAA

BBB\fbox{\myparbox{4em}{aa bb cc dd ee ff}}BBB
\end{document}

结果:

在此处输入图片描述

答案3

的可选参数必须\parbox包含特定标记(如果存在)。第一个的默认值为c,因此我们可以省去一些检查可选参数是否存在的麻烦。需要从最后一个开始。

第一个可选参数应该是c(默认),tb;第二个应该是长度;最后一个应该是ctbs(如果没有给出,则使用第一个)。

请注意,最后一个参数\myparbox应表示为+m,以便能够输入不同的段落。\deliverparbox使用宏是为了尽量减少代码重复。

\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand{\myparbox}{O{c}oom+m}{%
  \IfNoValueTF{#3}
   {%
    \IfNoValueTF{#2}
     {%
      \parbox[#1]{#4}{\deliverparbox{#5}}%
     }%
     {%
      \parbox[#1][#2]{#4}{\deliverparbox{#5}}%
     }%
   }%
   {%
    \parbox[#1][#2][#3]{#4}{\deliverparbox{#5}}%
   }
}
\NewDocumentCommand{\deliverparbox}{+m}{%
  \sloppy\setlength\parfillskip{0pt}#1%
}

\begin{document}

AAA\fbox{\parbox{4em}{aa bb cc dd ee ff}}AAA

BBB\fbox{\myparbox{4em}{aa bb cc dd ee ff}}BBB

BBB\fbox{\myparbox[t][12ex][s]{4em}{aa bb cc dd ee ff\par\vfil aa bb}}BBB

\end{document}

在此处输入图片描述

相关内容