
У меня есть команда с необязательным аргументом, и я хочу выполнить некоторый код в зависимости от того, является ли аргумент 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}