Anduvimos buscando en internet y de este modo mostrarte la solución a tu duda, si tienes alguna duda puedes dejar la duda y te contestamos porque estamos para servirte.
Solución:
Te hice una versión expandible de rnumexpr
que no requiere un delimitador y se detendrá en el primer no expandible, numexpr
-simbolo no valido. Eso intentos emular el comportamiento de numexpr
hasta cierto punto e ignore los pares de llaves.
La cosa sobre numexpr
, lo que ya todos comentaron, es que es un primitivo, por lo que sus reglas son diferentes a las reglas que gobiernan los reinos de los hombres que tratan con macros simples. Desafortunadamente, algunas cosas simplemente no se pueden hacer sin un apoyo primitivo.
Desea capacidad de expansión, por lo que, de inmediato, no puede tener anticipación (con futurelet
). futurelet
le permitiría mirar el siguiente token y decidir qué hacer con él. La capacidad de expansión te restringe a tomar tokens como argumentos y pasarlos de maneras divertidas, y tomar cosas como argumento (con un comando abierto como rnumexpr
) significa que:
rnumexpr 1+1
es imposible porque TeX te gritará cuando agarre}
rnumexpr 1+1 ⟨something else⟩
eventualmente agarrará⟨something else⟩
, sea lo que sea, determine si tiene que expandirse o no, y trátelo en consecuencia.
Con un argumento delimitado, podría usar algo como expl3
‘s __tl_act:NNNnn
para recorrer de forma expansible una lista de tokens y actuar sobre un elemento de manera diferente, dependiendo de si se trata de un espacio, una lista de tokens agrupada u otro token único, lo que facilitaría mucho la tarea en cuestión.
Primero déjame señalar algunas cosas sobre tu código. En tu prueba de vacuidad expandafterifxrelax#2relax
, los expandafter
salta ifx
y se expande relax
, por lo que no es de mucha utilidad y se puede quitar. Además, esta prueba puede imprimir caracteres no deseados si la entrada contiene un relax
. Por supuesto que estás en medio de una numexpr
, por lo que esto es simplemente quisquilloso.
Además, su condicional no termina en cada iteración de @rnumexpr
, pero solo al final del numexpr
. Esto, para expresiones grandes (y con grandes me refiero a suficientes copias de +1
para obtener un resultado superior a 1500–muy large) utilizan toda la pila de entrada de TeX. Y finalmente, tu definición no funciona para rnumexpr+1+1+1rrelax
y otras combinaciones de llaves (demasiado extrañas para ser consideradas como entrada normal).
Definí una emulación lenta, ciertamente subóptima, probablemente demasiado complicada, probablemente con errores, ⟨insertar-other-qualifiers-here⟩, de numexpr
. En general, el comportamiento es el mismo (en la medida de las pruebas que hice), excepto que ignora las llaves.
Comienza a escanear la entrada, token por token, y luego decide qué hacer con cada uno. Intenta expandir los tokens a medida que avanza y se detiene en el primer no expandible, numexpr
-simbolo no valido. Si esa ficha es relax
, se consume, como numexpr
lo hace, por lo que el comportamiento es muy similar en este aspecto.
La principal diferencia es que, como toma tokens como argumentos no delimitados, los espacios se ignoran, por lo que mientras que el resultado de thenumexpr 1+1 1
es 21
(2
adjunto con un 1
), el resultado de thernumexpr 1+1 1
es 12
(1+11
), por lo que necesita un token de finalización “más difícil” que numexpr
. Esto se puede evitar utilizando un relax
: thernumexpr 1+1relax 1
para terminar el rnumexpr
o usando obeyspaces
para que los espacios se envíen al subyacente numexpr
que luego hará lo correcto.
aquí está:
documentclassarticle
makeatletter
defrnumexprromannumeral-`0[email protected]
longdef[email protected]#1#2%
[email protected]#2%
%
[email protected]@[email protected]#2%
[email protected]#1#2%
[email protected]#1#2%
%
%
[email protected]#2%
%
[email protected]#2%
[email protected]#1%
[email protected]@after#1#2%
%
[email protected]#1#2%
%
def[email protected][email protected]
def[email protected]@after#1%
[email protected]@[email protected]expandafterrnumexpr#1[email protected][email protected]
def[email protected]@[email protected]#1#2%
ifx#2[email protected]
[email protected]@expandafter#1%
else
expandafter[email protected]@[email protected]
fi
#1expandafter#2%
def[email protected]@expandafter#1#2fi#3[email protected]%
fi#1romannumeral-`0[email protected]@unexpandable
longdef[email protected]@unexpandable#1%
expandafter[email protected]@[email protected]expandafter#1%
romannumeral-`0#1
longdef[email protected]@[email protected]#1#2%
ifx#1#2%
expandafter[email protected]
else
expandafter[email protected]
fi
#1#2
longdef[email protected]#1#2#2
longdef[email protected]#1#2relax#2
longdef[email protected]#1#2%
numexpr#1relax#2
longdef[email protected]#1%
ifx#1relax
expandafter@firstoftwo
else
expandafter@secondoftwo
fi
def[email protected]@[email protected]#1%
expandafter[email protected]@[email protected]@tokenexpandafternumber`#1
def[email protected]@[email protected]@token#1%
if
ifnum58>#1 1else xfi
ifnum #1>39 1else yfi
ifnum
ifnum#1=44 1else 0fi
ifnum#1=46 1else 0fi
=0
[email protected]
else
[email protected]
fi
else
ifnum#1=32
[email protected]
else
[email protected]
fi
fi
def[email protected]expandafter@firstoftworomannumeral-`0
def[email protected]expandafter@secondoftworomannumeral-`0
edef[email protected]thecatcode`&
catcode`&=11
longdef[email protected]#1&%
romannumeral-`0[email protected]@gobble#1[email protected] &
longdef[email protected]@gobble#1#2&%
ifx[email protected]#1%
expandafter[email protected]@[email protected]
else
expandafter[email protected]@tail
fi#2
def[email protected]@[email protected]
longdef[email protected]@tail#1[email protected] #1
longdef[email protected]#1%
[email protected]#1%
@secondoftwo%
%
ifrelaxexpandafter[email protected]detokenize#1&relax
expandafter@firstoftwo
else
expandafter@secondoftwo
fi
%
longdef[email protected]#1%
[email protected]#1%
@secondoftwo%
%
[email protected]@[email protected]@group#1%
@secondoftwo%
%
ifrelaxdetokenizeexpandafterexpandafter
expandafter[email protected]#1&relax
expandafter@firstoftwo
else
expandafter@secondoftwo
fi
%
%
longdef[email protected]@[email protected]@group#1%
ifcatexpandafter@gobbleexpandafterexpandafterstring#1?**%
expandafter@secondoftwo
else
expandafter@firstoftwo
fi
catcode`&=[email protected]
longdef[email protected]#1%
ifrelaxdetokenize#1relax
expandafter@firstoftwo
else
expandafter@secondoftwo
fi
makeatother
begindocument
deftwop+1+1
thenumexpr 1+1 1
thernumexpr 1+1 1
thenumexprtwop+1+1+1
thenumexprtwop+1+1+1
thenumexprtwop+1+1+1
thenumexprtwop+1+1+1+1+1
thenumexprtwop+1+1+1+1+1
thenumexpr 1+1
thenumexpr 1+1twop
deftwop+1+1
thernumexprtwop+1+1+1relax
thernumexprtwop+1+1+1relax
thernumexprtwop+1+1+1relax
thernumexprtwop+1+1+1+1+1relax
thernumexprtwop+1+1+1+1+1relax
thernumexpr 1+1
thernumexpr 1+1twop
Expandable! edefzthernumexpr+1+1+1+1relaxtextttmeaningz
thernumexpr1+1+1+1+1relax
thernumexpr1+1+1relax
thenumexpr1+1+1
Groups everywhere:
thernumexpr+1+1+1+1+1+1+1+1+1+1+1,
thernumexpr+1+1+1+1+1+1+1+1+1+1+1,
thernumexpr+1+1+1,
thernumexpr+1
No leftover:
detokenizeexpandafterthernumexpr+1+1+1relax
% thernumexpr1+1+1 STILL WON'T WORK :(
enddocument
La macro podría ser mucho más rápida si la expresión se evaluara con thenumexpr0
de antemano, en lugar de agarrar cada ficha y evaluarlas solo en el amargo final. Sin embargo, esto estropearía la “estabilidad” (si se le puede llamar así) de la macro porque en cada evaluación (tantos como grupos), un relax
se consumiría, por lo que para finalizar correctamente la macro tendría que recurrir a cosas como thernumexpr1+1+1+1relaxrelaxrelaxrelax
, así que opté por no participar en esta posibilidad.
La entrada para numexpr
termina cuando algo (inexpugnable) que no puede aparecer en un numexpr
es encontrado. Tenga en cuenta que numexpr
activa la expansión hasta que la entrada termina como se definió anteriormente.
Si el token que señaló el final de la expresión entera es relax
, se elimina por completo; por lo que no aparecerá si dices
edeftestthenumexpr1+1relax
que se expandiría a 2
.
No se permiten llaves en expresiones enteras, a menos que se utilicen para delimitar argumentos a macros que se expanden a medida que se escanea la expresión entera. Entonces
defaddition#1#2#1+#2
numexpraddition12relax
evaluará a 3
. Pero numexpr 1+1+1relax
es ilegal, porque el {
detiene el escaneo y el operando por primera vez +
Está perdido.
Puedes usar (
y )
para delimitar subexpresiones a evaluar con las reglas de precedencia habituales: numexpr2*(1+3)relax
evalúa a 8.
Sección de Reseñas y Valoraciones
Si sostienes algún reparo o capacidad de innovar nuestro ensayo te recordamos escribir una observación y con gusto lo estudiaremos.