Latex3: definir \tl_if_integer:n

Creado en 5 jul. 2021  ·  19Comentarios  ·  Fuente: latex3/latex3

Hola,

Será bueno probar si una lista de tokens es un número entero o no, sin recurrir al uso de __int_to_ roman:w interno:

\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:
   }
}

Comentario más útil

Estoy de acuerdo en que tendría sentido proporcionar \str_if_integer:nTF , pero aún no está claro cuáles deberían ser los números enteros permitidos. Presumiblemente, se deben permitir espacios entre signos, pero no dentro de un número entero, ya que TeX no lo permite.

El código basado en \romannumeral se rompe para largas cadenas de dígitos, con un error de "número demasiado grande". Presumiblemente, necesitamos un proceso más lento que solo tome unos pocos dígitos a la vez, pero luego se vuelve molesto detectar espacios entre dígitos.

Una alternativa/adición sería \str_to_integer:nF que desinfecta la cadena si se parece "suficientemente" a un número entero (podríamos decidir ser algo laxos (pero bien documentados)) y, de lo contrario, deja su segundo argumento en el flujo de entrada.

Todos 19 comentarios

Mejor 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:
      }
    }
}

El nombre parece extraño: en realidad no busca un número entero (por ejemplo -5 es un número entero pero devuelve falso, +7 también devuelve falso). Parece más una prueba si solo hay dígitos presentes.

@zauguin Está bien para el nombre, pero la función es útil, y haga coincidir el viejo tic del libro de texto para verificar si es un dígito. Estoy de acuerdo en que el entero podría implementarse usando expresiones regulares, pero será lento

Mejorado con tus comentarios:

\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 TeX acepta varios signos delante de un número, por lo que su prueba suele ser suficiente, pero no siempre. Si esto se implementara, podría permitir múltiples signos 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

La prueba es str para evitar la expansión de tokens en el argumento. Tanto la mía como su implementación no expanden el signo, pero expanden los dígitos con \romannumeral . Una versión tl probablemente tendría que expandir todo según sea necesario.

Estoy de acuerdo en que tendría sentido proporcionar \str_if_integer:nTF , pero aún no está claro cuáles deberían ser los números enteros permitidos. Presumiblemente, se deben permitir espacios entre signos, pero no dentro de un número entero, ya que TeX no lo permite.

El código basado en \romannumeral se rompe para largas cadenas de dígitos, con un error de "número demasiado grande". Presumiblemente, necesitamos un proceso más lento que solo tome unos pocos dígitos a la vez, pero luego se vuelve molesto detectar espacios entre dígitos.

Una alternativa/adición sería \str_to_integer:nF que desinfecta la cadena si se parece "suficientemente" a un número entero (podríamos decidir ser algo laxos (pero bien documentados)) y, de lo contrario, deja su segundo argumento en el flujo de entrada.

@blefloch ¿Cuál es el límite documentado de \romannumeral?

@bastien-roucaries El entero más grande que TeX puede manejar: 2³¹−1 = 2147483647.

@PhelypeOleinik Parece que @blefloch significa que +-+-+-+-+-+-+-+-+-+-+-+-+0000000000000000000000000000000000000000000000000000000000000000 podría romper \romannumeral...

Entonces, ¿cuál es el tamaño máximo de cadena?

@bastien-roucaries \romannumeral solo se rompe con "Número demasiado grande" para un número distinto de cero. TeX puede tomar una cadena de ceros arbitrariamente larga siempre que el entero resultante esté dentro del rango [−2³¹−1, 2³¹−1].

@bastien-roucaries @blefloch No olvidaría los números enteros en formato hexadecimal u octal. Y

-`a

es un entero también.

hay una prueba interna para dígitos en l3bitset \__bitset_test_digits:nTF . No maneja signos ya que esto no era necesario, pero debería manejar expresiones enteras.

como @ eg9 acaba de insinuar, ¿cuál es el caso de uso real aquí? ¿Es una verificación de documento a nivel de usuario para una cadena de dígitos, o una verificación de que la cadena es una entrada válida para una función de entero expl3? Este último parece más útil en un contexto expl3, y básicamente significa que no queda nada después \numexpr#1 por lo que no sería necesaria la verificación lenta de cadenas literales de dígitos.

@davidcarlisle Este error se trata del primer caso, pero me gustaría tener el segundo uso

No creo que esté a favor de extender la capa de programación L3 con extensiones aleatorias que son (posiblemente) útiles en situaciones especiales pero que no tienen casos de uso claros que se necesitan regularmente. Para mí este es uno de esos ejemplos. Si empezamos con eso, ¿dónde terminamos? ¿Cuántos "es esto tl alguna X" especial deberíamos admitir entonces? Mi voto sobre esto es no; no para el lenguaje central.

@FrankMittelbach Saber si podemos hacer algunos cálculos o no en TL es útil. El otro podría hacerse usando expresiones regulares, pero con el inconveniente de que no funciona en contexto expandido (y necesito esta prueba para que funcione en contexto expandido)

No hay duda. Pero, ¿es lo suficientemente útil como para garantizar su inclusión en el lenguaje central (o solo para proporcionarse como parte de algún código de paquete cuando realmente se necesita)? Esa es la pregunta para mí aquí y hasta ahora no he visto realmente argumentos que favorezcan su inclusión.

Puede hacer la misma pregunta para "es una dimensión", "es como saltar", "son solo letras", "contiene caracteres que no son ASCII", "es un formato de fecha" y, y, y... las posibilidades son bastante abiertas y para la mayoría de ellas puede construir uno o dos casos de uso. Pero el 99% de las veces simplemente se quedarán sentados y ocuparán espacio. Y aunque el espacio no es tan importante como lo era en el pasado, todavía se suma a la complejidad y capacidad de mantenimiento del sistema central. Entonces, de nuevo, ¿esta funcionalidad tiene un uso amplio y repetido? En caso afirmativo, y escucho argumentos convincentes a favor de que podría considerarse un candidato para su inclusión. Si no, debe implementarse como parte del código que lo necesita.

@FrankMittelbach El problema es específico de biblatex aquí. Necesitamos probar si algún campo es un número entero (piense en el número de páginas) y luego hacer algo de aritmética en él, en un contexto expandible.
Ok, ti ​​es específico, pero la parte complicada son las cosas expandibles.
Puede ser que este tipo de prueba solo deba documentarse. Al leer el documento, no sé cómo hacerlo y, además, biblatex core cree que no es posible probar (expandir compatible) si un token es un número entero.

Puede ser que la solución sea hacer que la expresión regular sea expandible (creo que será bueno)

No me malinterpreten, no estoy en absoluto en contra de que lo ayudemos en el lado de biblatex para que esto funcione, y es posible que en el núcleo nos falte alguna funcionalidad que debería estar en el núcleo para respaldar eso. Mi punto es que el núcleo debe restringirse a las necesidades que son "generales" y proporcionar la base general básica para escribir código especial, pero no proporcionar todo tipo de extensiones que se usan muy pocas veces (por ejemplo, en este caso cuando biblatex no se usa). De lo contrario, eventualmente terminaremos con un conjunto de comandos muy inflado.

Hacer que las cosas funcionen de manera expandible generalmente tiene un alto precio, ya sea en funcionalidad limitada o pérdida de velocidad o ambos. Así que dudo que sea una buena idea tratar de hacer que las expresiones regulares sean ampliables, pero dejo que @blefloch comente al respecto.

Pero sin conocer su caso de uso con más detalle: en algún lugar se están configurando sus campos y eso no se hace de manera expandible ya que requerirá asignaciones, por lo que en esa etapa podría determinar si tiene un número entero o algo más y registrar ese hecho que podría luego se puede usar de manera expandible (no estoy seguro de que eso ayude o sea factible, pero evitaría probar el campo una y otra vez).

¿Fue útil esta página
0 / 5 - 0 calificaciones