Latex3: defina \tl_if_integer:n

Criado em 5 jul. 2021  ·  19Comentários  ·  Fonte: latex3/latex3

Oi,

Será bom testar se uma lista de tokens é um número inteiro ou não, sem recorrer ao uso interno de __int_to_ roman:w :

\prg_new_conditional:Npnn \tl_if_integer:n #1 { p, T, F, TF }
{
  \tl_if_blank:oTF { \__int_to_roman:w -0#1 }
   {
    \prg_return_true:
   }
   {
    \prg_return_false:
   }
}

Comentários muito úteis

Concordo que faria sentido fornecer \str_if_integer:nTF , mas ainda não está claro quais devem ser os inteiros permitidos. Presumivelmente, os espaços devem ser permitidos entre os sinais, mas não dentro de um inteiro, pois o TeX não permite isso?

Código baseado em quebras \romannumeral para longas sequências de dígitos, com um erro "número muito grande". Presumivelmente, precisamos de um processo mais lento que pegue apenas alguns dígitos de cada vez, mas fica irritante detectar espaços entre os dígitos.

Uma alternativa/adição seria \str_to_integer:nF que desinfeta a string se parecer "suficiente" como um inteiro (podemos decidir ser um pouco relaxado (mas bem documentado)) e, caso contrário, deixa seu segundo argumento no fluxo de entrada.

Todos 19 comentários

Melhor aqui:

\prg_new_conditional:Npnn \tl_if_integer:n #1 { p, T, F, TF }
{
  \tl_if_blank:nTF{#1}
    {
      \prg_return_false:
    }
    {
      \tl_if_blank:oTF { \__int_to_roman:w -0#1 }
      {
        \prg_return_true:
      }
      {
        \prg_return_false:
      }
    }
}

O nome parece estranho: Na verdade, ele não verifica se há um inteiro (por exemplo -5 é um inteiro, mas retorna falso, +7 também retorna falso). Parece mais um teste se apenas dígitos estiverem presentes.

@zauguin Ok para o nome, mas a função é útil e corresponde ao antigo carrapato do livro tex para verificar se é dígito. Eu concordo que o inteiro pode ser implementado usando regex, mas será lento

Melhorado com seus comentários:

\prg_new_conditional:Npnn \tl_if_digit:n #1 { p, T, F, TF }
{
  \tl_if_blank:nTF{#1}
    {
      \prg_return_false:
    }
    {
      \tl_if_blank:oTF { \__int_to_roman:w -0#1 }
      {
        \prg_return_true:
      }
      {
        \prg_return_false:
      }
    }
  }
\prg_generate_conditional_variant:Nnn \tl_if_digit:n { o } { p, T, F, TF }
\prg_new_conditional:Npnn \__tl_if_integer:n #1 { p, T, F, TF }
{
    \exp_args:No\str_if_eq:onTF{\tl_head:n{#1}}{+}
    {
      \exp_args:No\tl_if_digit:oTF{\tl_tail:n{#1}}
      {
        \prg_return_true:
      }
      {
        \prg_return_false:
      }
    }
    {
      \exp_args:No\str_if_eq:onTF{\tl_head:n{#1}}{-}
      {
        \exp_args:No\tl_if_digit:oTF{\tl_tail:n{#1}}
        {
          \prg_return_true:
        }
        {
          \prg_return_false:
        }
      }
      {
        \prg_return_false:
      }
    }
}
\prg_new_conditional:Npnn \tl_if_integer:n #1 { p, T, F, TF }
{
  % fast path
  \tl_if_digit:nTF{#1}
  {
    \prg_return_true:
  }
  {
    % slow path
    \__tl_if_integer:nTF{#1}
    {
      \prg_return_true:
    }
    {
      \prg_return_false:
    }
  }
}

@bastien-roucaries O TeX aceita vários sinais na frente de um número, então seu teste geralmente é suficiente, mas nem sempre. Se isso for implementado, poderá permitir vários sinais como este:

\ExplSyntaxOn
\prg_new_conditional:Npnn \str_if_integer:n #1 { p, T, F, TF }
  { \exp_after:wN \__str_if_integer_sign:N \tl_to_str:n {#1} \scan_stop: }
\cs_new:Npn \__str_if_integer_sign:N #1
  {
    \if:w $
        \if_meaning:w - #1 F \fi:
        \if_meaning:w + #1 F \fi: $
      \exp_after:wN \__str_if_integer_digits:w \exp_after:wN #1
    \else:
      \exp_after:wN \__str_if_integer_sign:N
    \fi:
  }
\cs_new:Npn \__str_if_integer_digits:w #1 \scan_stop:
  {
    \tl_if_blank:nTF {#1}
      { \prg_return_false: }
      {
        \tl_if_blank:oTF { \__int_to_roman:w -0#1 }
          { \prg_return_true: }
          { \prg_return_false: }
      }
  }

\cs_new:Npn \test #1
  { \typeout { #1: \str_if_integer:nTF {#1} { INT } { NOT } } }

\test {   }
\test { ~ }
\test { 1 }
\test { - }
\test { -1 }
\test { +1 }
\test { +-+-+-1 }

\stop

O teste é str para evitar a expansão de tokens no argumento. Tanto a minha quanto a sua implementação não expandem o sinal, mas expandem os dígitos com \romannumeral . Uma versão tl provavelmente teria que expandir tudo conforme necessário.

Concordo que faria sentido fornecer \str_if_integer:nTF , mas ainda não está claro quais devem ser os inteiros permitidos. Presumivelmente, os espaços devem ser permitidos entre os sinais, mas não dentro de um inteiro, pois o TeX não permite isso?

Código baseado em quebras \romannumeral para longas sequências de dígitos, com um erro "número muito grande". Presumivelmente, precisamos de um processo mais lento que pegue apenas alguns dígitos de cada vez, mas fica irritante detectar espaços entre os dígitos.

Uma alternativa/adição seria \str_to_integer:nF que desinfeta a string se parecer "suficiente" como um inteiro (podemos decidir ser um pouco relaxado (mas bem documentado)) e, caso contrário, deixa seu segundo argumento no fluxo de entrada.

@blefloch Qual é o limite documentado de \romannumeral ?

@bastien-roucaries O maior inteiro que o TeX pode manipular: 2³¹−1 = 2147483647.

@PhelypeOleinik Parece que @blefloch significa que +-+-+-+-+-+-+-+-+-+-+-+-+00000000000000000000000000000000000000000000000000000000000000 poderia quebrar \ romannumeral ...

Então, qual é o tamanho máximo da string?

@bastien-roucaries \romannumeral apenas quebra com “Número muito grande” para um número diferente de zero. O TeX pode receber uma string arbitrariamente longa de zeros desde que o inteiro resultante esteja dentro do intervalo [−2³¹−1, 2³¹−1].

@bastien-roucaries @blefloch Eu não esqueceria inteiros em formato hexadecimal ou octal. E

-`a

é um número inteiro também.

há um teste interno para dígitos em l3bitset \__bitset_test_digits:nTF . Ele não lida com sinais, pois isso era desnecessário, mas deve lidar com expressões inteiras.

como o @eg9 acabou de sugerir, qual é o caso de uso real aqui? É uma verificação de documento de nível de usuário para uma sequência de dígitos ou uma verificação de que a sequência é uma entrada válida para uma função de inteiro expl3. O último parece mais útil em um contexto expl3, e basicamente significa que nada resta depois de \numexpr#1 então a verificação lenta de strings literais de dígitos não seria necessária.

@davidcarlisle Este bug é sobre o primeiro caso, mas eu gostaria de ter o segundo uso

Eu não acho que sou a favor de estender a camada de programação L3 com extensões aleatórias que são (possivelmente) úteis em situações especiais, mas não têm casos de uso claros e regularmente necessários. Para mim este é um desses exemplos. Se começarmos com isso, onde vamos parar? Quantos "isto é tl algum X" especial devemos suportar então? Meu voto sobre isso é não; não para o idioma principal.

@FrankMittelbach Sabendo que podemos fazer alguma computação ou não em TL é útil. O outro poderia ser feito usando regex, mas com a armadilha de não funcionar em contexto de expansão (e preciso que esse teste funcione em contexto de expansão)

Sem dúvida. Mas é útil o suficiente para garantir sua inclusão na linguagem principal (ou apenas para ser fornecido como parte de algum código de pacote quando realmente necessário)? Essa é a questão para mim aqui e até agora não vi realmente argumentos que favoreçam sua inclusão.

Você pode fazer a mesma pergunta para "é uma dimensão", "é como pular", "é apenas letras", "contém caracteres não ASCII", "é um formato de data" e, e, e ... as possibilidades são bastante abertas e para a maioria delas você pode construir um ou dois casos de uso. Mas 99% do tempo eles ficam sentados e ocupam espaço. E embora o espaço não seja um prêmio como era no passado, ainda aumenta a complexidade e a capacidade de manutenção do sistema central. Então, novamente, essa funcionalidade é de uso amplo e repetido? Se sim, e ouço argumentos convincentes para que possa ser considerado um candidato à inclusão. Caso contrário, ele deve ser implementado como parte do código que precisa dele.

@FrankMittelbach O problema é específico do biblatex aqui. Precisamos testar se algum campo é um inteiro (pense no número de páginas) e então fazer alguma aritmética nele, em um contexto expansível.
Ok ti é específico, mas a parte complicada é o material expansível.
Pode ser que esse tipo de teste só deva ser documentado. Lendo o doc eu não sei como fazer, e além disso o core biblatex acha que não é possível testar (expandir comptabible) se um token é um inteiro.

Pode ser que a solução seja tornar o regex expansível (acho que será legal)

Não me interpretem mal, eu não sou contra que nós o ajudemos no lado da biblatex a fazer isso funcionar, e pode ser que no núcleo estejamos faltando algumas funcionalidades que deveriam estar no núcleo para dar suporte a isso. Meu ponto é que o núcleo deve se restringir às necessidades que são "gerais" e fornecer a base geral básica para escrever código especial, mas não fornecer todos os tipos de extensões que são usadas muito raramente (por exemplo, neste caso quando o biblatex não é usado). Caso contrário, acabaremos com um conjunto de comandos muito inchado.

Fazer com que as coisas funcionem de forma expansível geralmente vem com um preço alto, seja em funcionalidade limitada ou perda de velocidade ou ambos. Portanto, duvido que seja uma boa ideia tentar tornar o regex expansível, mas deixo @blefloch comentar sobre isso.

Mas sem conhecer seu caso de uso com mais detalhes: em algum lugar seus campos estão sendo configurados e isso não é feito de forma expansível, pois exigirá atribuições, então nesse estágio você pode determinar se tem um número inteiro ou outra coisa e registrar esse fato que poderia então ser usado de forma expansível (não tenho certeza se ajuda ou é viável, mas evitaria testar o campo repetidamente).

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

stone-zeng picture stone-zeng  ·  25Comentários

josephwright picture josephwright  ·  31Comentários

dbitouze picture dbitouze  ·  4Comentários

JairoAdelRio picture JairoAdelRio  ·  7Comentários

svitalsky picture svitalsky  ·  11Comentários