这是带分组的 LaTeX3 条件编译失败. 我想写一个条件标记列表expl3
完全可扩展的标记列表条件,以便将其用作谓词条件。受到 Joseph Wright 的启发评论我想到了一个递归实现,但我不知道如何将它放入expl3
语法中。
为了解答这个问题,让我们实现一个函数,检查它的参数是否是整数,即仅由数字组成。将参数保存在本地标记列表中,然后运行适当的测试很简单。但是,由于赋值,生成的代码不可扩展。如果没有赋值,可能的解决方案可能如下所示。
\prg_new_conditional:Npnn \is_integer:n #1 { p, T, F, TF }
{
\tl_if_empty:nTF { #1 }
{
% We are done if the token list is empty
\prg_return_true:
}{
\exp_args:NNx \tl_if_in:nnTF { 0123456789 } { \tl_head:n { #1 } }
{
% Call \is_integer:n with \tl_tail:n { #1 }
}{
\prg_return_false:
}
}
}
有没有办法\is_integer:n
在指示的行中再次调用?据我所知,所需的实现是可扩展的,因为对于任何给定的输入,TeX 所做的标记替换最终都会终止。当然,我们也欢迎具有相同结果的替代方法。
顺便说一句,我知道已有的实现,例如在xstring
包中。但是,我需要根据自己的需求进行调整,不能使用这样的解决方案。
答案1
检查标记列表是否<tl>
仅由数字组成的旧技巧是使用\romannumeral-<tl>
,在这种情况下它将不返回任何内容。
据我所知,中没有用于该技巧的公共接口expl3
,只有\__int_to_roman:w
:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\prg_new_conditional:Npnn \is_integer:n #1 { p, T, F, TF }
{
\tl_if_blank:oTF { \__int_to_roman:w -0#1 }
{
\prg_return_true:
}
{
\prg_return_false:
}
}
\NewDocumentCommand{\isinteger}{m}
{
#1~is \bool_if:nF { \is_integer_p:n {#1} } {~not}~an~integer
}
\ExplSyntaxOff
\begin{document}
\isinteger{42}
\isinteger{2ab1}
\end{document}
答案2
为了回答我自己的问题,仅使用可扩展宏并避免使用\prg_new_conditional:Npnn
以下示例就可以了,并且灵活,所有使用的测试都可以适应特定问题,而不必依赖于\__int_to_roman:w
egreg 建议的预定义代码。
\documentclass{article}
\usepackage{expl3}
\begin{document}
\ExplSyntaxOn
\bool_new:N \true_bool
\bool_new:N \false_bool
\bool_gset_true:N \true_bool
\bool_gset_false:N \false_bool
\prg_new_conditional:Npnn \is_digit:N #1 { TF }
{
\bool_if:nTF
{
\token_if_eq_charcode_p:NN 0 #1 ||
\token_if_eq_charcode_p:NN 1 #1 ||
\token_if_eq_charcode_p:NN 2 #1 ||
\token_if_eq_charcode_p:NN 3 #1 ||
\token_if_eq_charcode_p:NN 4 #1 ||
\token_if_eq_charcode_p:NN 5 #1 ||
\token_if_eq_charcode_p:NN 6 #1 ||
\token_if_eq_charcode_p:NN 7 #1 ||
\token_if_eq_charcode_p:NN 8 #1 ||
\token_if_eq_charcode_p:NN 9 #1
}{
\prg_return_true:
}{
\prg_return_false:
}
}
\cs_new:Npn \is_integer_p:n #1
{
\tl_if_empty:nTF { #1 }
{
% We are done if the token list is empty
\bool_if_p:n { \true_bool }
}{
\exp_args:Nf \is_digit:NTF { \tl_head:n { #1 } }
{
\exp_args:Nf \is_integer_p:n { \tl_tail:n { #1 } }
}{
\bool_if_p:n { \false_bool }
}
}
}
\bool_if:nTF { \is_integer_p:n { 1234 } } { true } { false }
\ExplSyntaxOff
\end{document}
有趣的是,尝试使用相同的方法\prg_new_conditional:Npnn
似乎是不可能的。下面的代码会抛出错误,尽管我不明白为什么。我假设这两种实现都会产生等效的代码,但显然事实并非如此。
\prg_new_conditional:Npnn \is_integer_prg:n #1 { p }
{
\tl_if_empty:nTF { #1 }
{
% We are done if the token list is empty
\prg_return_true:
}{
\exp_args:Nf \is_digit:NTF { \tl_head:n { #1 } }
{
\exp_args:Nf \is_integer_prg_p:n { \tl_tail:n { #1 } }
}{
\prg_return_false:
}
}
}
也许有人可以解释为什么该\prg_new_conditional:Npnn
解决方案不起作用。
编辑:最终我弄清楚了如何使用\prg_new_conditional:Npnn
。我之前尝试的问题是谓词条件不是 的合法“返回值” \prg_new_conditional:Npnn
。这意味着
\prg_new_conditional:Npnn \foo: { p }
{
\int_compare_p:n { 1 = 2 }
}
失败,而
\prg_new_conditional:Npnn \foo: { p }
{
\int_compare:nTF { 1 = 2 } { \prg_return_true: } { \prg_return_false: }
}
有效,事后看来当然是有道理的。因此,上述尝试可以更正为以下有效示例:
\documentclass{article}
\usepackage{expl3}
\begin{document}
\ExplSyntaxOn
\prg_new_conditional:Npnn \is_digit:N #1 { TF }
{
\bool_if:nTF
{
\token_if_eq_charcode_p:NN 0 #1 ||
\token_if_eq_charcode_p:NN 1 #1 ||
\token_if_eq_charcode_p:NN 2 #1 ||
\token_if_eq_charcode_p:NN 3 #1 ||
\token_if_eq_charcode_p:NN 4 #1 ||
\token_if_eq_charcode_p:NN 5 #1 ||
\token_if_eq_charcode_p:NN 6 #1 ||
\token_if_eq_charcode_p:NN 7 #1 ||
\token_if_eq_charcode_p:NN 8 #1 ||
\token_if_eq_charcode_p:NN 9 #1
}{
\prg_return_true:
}{
\prg_return_false:
}
}
\prg_new_conditional:Npnn \is_integer:n #1 { p, TF }
{
\tl_if_empty:nTF { #1 }
{
% We are done if the token list is empty
\prg_return_true:
}{
\exp_args:Nf \is_digit:NTF { \tl_head:n { #1 } }
{
\exp_args:Nf \is_integer:nTF { \tl_tail:n { #1 } }
{
\prg_return_true:
}{
\prg_return_false:
}
}{
\prg_return_false:
}
}
}
\bool_if:nTF { \is_integer_p:n { 1234 } } { true } { false },~
\bool_if:nTF { \is_integer_p:n { 12ab } } { true } { false }
\ExplSyntaxOff
\end{document}
正如预期的那样,这将产生文档中的文本。当然,正如 Manuel 所指出的,可以通过定义和的适当变体来避免true, false
使用。此处标记为已解决。\exp_args:Nf
\is_digit:NTF
\is_integer:NTF