使用 expl3 编写条件标记列表

使用 expl3 编写条件标记列表

这是带分组的 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:wegreg 建议的预定义代码。

\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

相关内容