Пустой необязательный аргумент или отсутствие необязательного аргумента вообще?

Пустой необязательный аргумент или отсутствие необязательного аргумента вообще?

Я узнал, что \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тестов для правильного определения аргументов, поскольку первый метод кажется хрупким, а второй — слишком многословным и повторяющимся. Подход, аналогичныйОтвет Марийнможет быть альтернативой, но, по крайней мере, в этом случае также требуется глубокое знание определения \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}

Обратите внимание, что это изменяет поведение всех парбоксов. Если вы хотите пользовательскую команду с выравниванием по ширине и при этом сохранить обычную команду, то вы можете определить пользовательскую команду, используя копию команды, \@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(по умолчанию) tили b; второй должен быть длиной; последний должен быть c, t, bили s(если не указан, используется первый).

Обратите внимание, что последний аргумент должен \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}

введите описание изображения здесь

Связанный контент