Как проверить логический аргумент в команде с необязательными аргументами?

Как проверить логический аргумент в команде с необязательными аргументами?

У меня есть команда с необязательным аргументом, и я хочу выполнить некоторый код в зависимости от того, является ли аргумент trueили false(я уверен, что эта команда всегда будет иметь некоторый аргумент, преобразуемый в логическое значение, потому что это будет частная команда, а не пользовательская команда). С моим кодом я получаю эту ошибку:

! Missing number, treated as zero.
<to be read again> 
                   t
l.8     \test{
              }
?

Спасибо всем за любую помощь.

\documentclass{article}
\usepackage{expl3}
\begin{document}
\ExplSyntaxOn
\newcommand{\test}[1][true]{
\bool_if:NTF{#1}{\message{true}}{\message{false}}
}
\test{}
\ExplSyntaxOff
\end{document}

решение1

Во-первых, обратите внимание, что \bool_if:N(TF)ожидает один токен (-type N) в качестве аргумента, поэтому \bool_if:NTF {true} {T}{F}синтаксически недопустим. Вам понадобится nаргумент -type: \bool_if:nTF {true} {T}{F}. Однако это тоже не работает, поскольку expl3булевы функции не понимают литералы trueи false, поэтому вам нужно помочь ему понять, что вы имеете в виду.

Например, можно использовать \str_case:nnFдля проверки входного аргумента на соответствие ряду предопределенных случаев и, если ни один из них не соответствует, перейти к следующей Fветви, что позволяет \bool_if:n(TF)выполнить синтаксический анализ:

\documentclass{article}
\usepackage{xparse}
\begin{document}
\ExplSyntaxOn
\NewDocumentCommand \test { O{true} }
  {
    \bool_if:nTF
      {
        \str_case:nnF {#1}
          { % Known cases
            { true  } { \c_true_bool  }
            { T     } { \c_true_bool  }
            { 1     } { \c_true_bool  }
            %
            { false } { \c_false_bool }
            { F     } { \c_false_bool }
            { 0     } { \c_false_bool }
          }
          {#1} % Otherwise
      }
      { \iow_term:n {true} }
      { \iow_term:n {false} }
  }
%
\test % no argument
\test[true]  \test[1] \test[T] \test[\c_true_bool]  % true input
\test[false] \test[0] \test[F] \test[\c_false_bool] % false input
\test[\int_compare_p:n { 2+2>4 } && !\c_false_bool] % expressions
%
\ExplSyntaxOff
\end{document}

Будет напечатано:

true
true
true
true
true
false
false
false
false
false

Обратите внимание, что это не защищает от произвольно неверного ввода, а просто охватывает несколько дополнительных случаев, поэтому вы не сможете использоватьчто-либов качестве входных данных. Кроме того, литералы trueи falseраспознаются только если используются по отдельности. То есть \test[true]и \test[false]работают как и ожидалось, но \test[!true]не будут, поскольку !trueне распознаются \str_case:nn(TF), и литерал trueзатем переходит непосредственно к \bool_if:n(TF), который затем терпит неудачу, как и прежде.

Кроме того, если это команда для частного использования, которая гарантированно будет иметь аргумент, то нет смысла делать аргумент необязательным, поскольку это только замедлит обработку.

решение2

Вы не дали много подробностей о том, что должна делать ваша команда. Но вместо того, чтобы использовать аргументы "true" и "false", а затем сравнивать их строки, обычно лучше использовать синтаксис key val в аргументе и устанавливать с ними реальные булевы значения:

\documentclass{article}
\usepackage{expl3}
\begin{document}
\ExplSyntaxOn
\keys_define:nn { alek }
 {
   dothis .bool_set:N = \l__alex_dothis_bool
 }

\newcommand{\test}[1][]
 {
  \keys_set:nn {alek}{dothis=true,#1} 
  \bool_if:NTF\l__alex_dothis_bool
   {true}
   {false}
 }
\ExplSyntaxOff

\test{}

\test[dothis]

\test[dothis=false]

\test[]
\end{document}

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