El escenario: leer una fecha en un yyyy-mm-dd
formulario de un archivo a un cs. Este CS luego se compara con una macro de 'fecha actual' para escribir algunos argumentos de una manera específica en un archivo externo. La macro del día actual está en la línea de
% \def\TODAY{}
% \def\Today{\the\year-\TwoDigits{\the\month}-\TwoDigits{\the\day} }
\def\TODAY{\xdef\Today{\the\year-\TwoDigits{\the\month}-\TwoDigits{\the\day}}}
Esto funciona para etiquetar cosas, ya que \ref{yyyy-mm-dd}
funciona según lo previsto. Al no tener extra \TODAY
y luego usar \def
'd Today, es la comparación la que no funciona. No etoolbox
es \ifstrequal
lo que usé antes. Cada vez que cambiaba la fecha, usaba una sola \xdef
y luego pasaba esa macro a a \ifx
, y para que funcionara tenía que definir la fecha con un adjunto.editarLeer para mi asombro inserta un solo espacio después de lo que se ha leído.
Actualmente supuestamente estoy arreglando cosas, pero lo rompí de alguna manera y ahora no coincide en absoluto. El primer culpable fue que mi \TwoDigits
cmd era robusto, cambiándolo de nuevo \def
en lugar de \NewDocumentCommand
arreglarlo. Este último es para comandos a nivel de usuario, así que lo dejaré escapar. Pero los resultados del mwe no me quedan claros.
0.txt
contiene una línea con 2001-01-01
y una línea nueva después, como si se hubiera escrito una línea y se hubiera cerrado la salida.
Las preguntas:
- ¿Cuál es la forma "correcta" de comparar cosas (macro, cs, comando?) que (debería) expandirse a cadenas?
- ¿Por qué no
\edef
trabajar\xdef
aquí? Pensé que era una expansión completa y, de hecho, antes (mi control de versiones está casi ausente, así que no puedo dar un mwe por esto) funcionó. - ¿Cuál es el significado de la robustez? ¿Existe una regla general sencilla sobre cuándo es necesario, obligatorio o irrelevante?
- Está trabajando con
xstring
's\IfStrEqual
solosise inserta en la definición de
\datemacro
, en lugar de entre corchetes de comparación, es decir,{\datemacro }
. ¿Por qué? \ifstrequal
supuestamente no se expande; lo usé una vez en un comando para probar si un argumento es igual a&
, esto funciona. ¿Se está convirtiendo el número 1 en lo que sea que se ingresó y no cuenta como una expansión?
editar: Olvidé \ifx
que se usaba para macros, no para argumentos delimitados, lo siento.
Ejemplo 1;
\documentclass{article}
\usepackage[top=1.5cm, bottom=0.6cm, hmargin=1.5cm]{geometry}
\usepackage{etoolbox}
\newread\periods
\openin\periods=0.txt
\begin{document}\setlength\parindent{0pt}\fontsize{20}{20}\selectfont
\def\testi{2001-01-01}
\edef\testii{2001-01-01}
\def\testiii{2001-01-01 }
\edef\testiiii{2001-01-01 }
\global\read\periods to \DDD
\ifstrequal{\testi}{2001-01-01}{T\\}{F\\}% F
\ifstrequal{\testii}{2001-01-01}{T\\}{F\\}% F
\ifstrequal{\testiii}{2001-01-01}{T\\}{F\\}% F
\ifstrequal{\testiiii}{2001-01-01}{T\\}{F\\}% F
\ifstrequal{\DDD}{2001-01-01}{T\\}{F\\}% F
\ifstrequal{\testi}{\DDD}{T\\}{F\\}% F
\ifstrequal{\testii}{\DDD}{T\\}{F\\}% F
\ifstrequal{\testiii}{\DDD}{T\\}{F\\}% F
\ifstrequal{\testiiii}{\DDD}{T\\}{F\\}% F
\ifstrequal{\DDD}{\DDD}{T\\}{F\\}% T
\ifx{\testi}{2001-01-01} T\\\else F\\\fi% F
\ifx{\testii}{2001-01-01} T\\\else F\\\fi% F
\ifx{\testiii}{2001-01-01} T\\\else F\\\fi% F
\ifx{\testiiii}{2001-01-01} T\\\else F\\\fi% F
\ifx{\DDD}{2001-01-01} T\\\else F\\\fi% F
\ifx{\testi}{\DDD} T\\\else F\\\fi% F
\ifx{\testii}{\DDD} T\\\else F\\\fi% F
\ifx{\testiii}{\DDD} T\\\else F\\\fi% F
\ifx{\testiiii}{\DDD} T\\\else F\\\fi% F
\ifx{\DDD}{\DDD} T\\\else F\\\fi% F
\ifcsequal{\testi}{\DDD}{T\\}{F\\}% F
\ifcsequal{\testii}{\DDD}{T\\}{F\\}% F
\ifcsequal{\testiii}{\DDD}{T\\}{F\\}% F
\ifcsequal{\testiiii}{\DDD}{T\\}{F\\}% F
\ifcsequal{\DDD}{\DDD}{T\\}{F\\}% F
\ifdefequal{\testi}{\DDD}{T\\}{F\\}% F
\ifdefequal{\testii}{\DDD}{T\\}{F\\}% F
\ifdefequal{\testiii}{\DDD}{T\\}{F\\}% T
\ifdefequal{\testiiii}{\DDD}{T\\}{F\\}% T
\ifdefequal{\DDD}{\DDD}{T\\}{F\\}% T
\end{document}
ejemplo 2;
\documentclass{article}
\usepackage[top=1.5cm, bottom=0.6cm, hmargin=1.5cm]{geometry}
\usepackage{etoolbox,xstring}
\def\TwoDigits#1{\ifnum#1<10 0#1\else#1\fi}
\newcount\month
\month 1\relax
\newcount\day
\day 1\relax
\newread\periods
\openin\periods=0.txt
\global\read\periods to \DDD
\def\testi{2001-\TwoDigits{\the\month}-\TwoDigits{\the\day}}%
\edef\testii{2001-\TwoDigits{\the\month}-\TwoDigits{\the\day}}%
\def\testiii{2001-\TwoDigits{\the\month}-\TwoDigits{\the\day} }%
\edef\testiiii{2001-\TwoDigits{\the\month}-\TwoDigits{\the\day} }%
\begin{document}\setlength\parindent{0pt}
DDD is \DDD.% space between cs and .
\ifstrequal{\testi}{2001-01-01}{T\\}{F\\}% F
\ifstrequal{\testii}{2001-01-01}{T\\}{F\\}% F
\ifstrequal{\testiii}{2001-01-01}{T\\}{F\\}% F
\ifstrequal{\testiiii}{2001-01-01}{T\\}{F\\}% F
\ifstrequal{\DDD}{2001-01-01}{T\\}{F\\}% F
\ifstrequal{\testi}{\DDD}{T\\}{F\\}% F
\ifstrequal{\testii}{\DDD}{T\\}{F\\}% F
\ifstrequal{\testiii}{\DDD}{T\\}{F\\}% F
\ifstrequal{\testiiii}{\DDD}{T\\}{F\\}% F
\ifstrequal{\DDD}{\DDD}{T\\}{F\\}% T
\ifx\testi{2001-01-01} T\\\else F\\\fi% F
\ifx\testii{2001-01-01} T\\\else F\\\fi% F
\ifx\testiii{2001-01-01} T\\\else F\\\fi% F
\ifx\testiiii{2001-01-01} T\\\else F\\\fi% F
\ifx\DDD{2001-01-01} T\\\else F\\\fi% F
\ifx\testi\DDD T\\\else F\\\fi% F
\ifx\testii\DDD T\\\else F\\\fi% F
\ifx\testiii\DDD T\\\else F\\\fi% F
\ifx\testiiii\DDD T\\\else F\\\fi% T
\ifx\DDD\DDD T\\\else F\\\fi% T
\ifcsequal{\testi}{\DDD}{T\\}{F\\}% F
\ifcsequal{\testii}{\DDD}{T\\}{F\\}% F
\ifcsequal{\testiii}{\DDD}{T\\}{F\\}% F
\ifcsequal{\testiiii}{\DDD}{T\\}{F\\}% F
\ifcsequal{\DDD}{\DDD}{T\\}{F\\}% F
\ifdefequal{\testi}{\DDD}{T\\}{F\\}% F
\ifdefequal{\testii}{\DDD}{T\\}{F\\}% F
\ifdefequal{\testiii}{\DDD}{T\\}{F\\}% F
\ifdefequal{\testiiii}{\DDD}{T\\}{F\\}% T
\ifdefequal{\DDD}{\DDD}{T\\}{F\\}% T
\IfStrEq{\testi}{\DDD}{T\\}{F\\}% F
\IfStrEq{\testii}{\DDD}{T\\}{F\\}% F
\IfStrEq{\testi }{\DDD}{T\\}{F\\}% F
\IfStrEq{\testii }{\DDD}{T\\}{F\\}% F
\IfStrEq{\testiii}{\DDD}{T\\}{F\\}% T
\IfStrEq{\testiiii}{\DDD}{T\\}{F\\}% T
\IfStrEq{\DDD}{\DDD}{T\\}{F\\}% T
\end{document}
Respuesta1
\ifstrequal
De la documentación de etoolbox
:
\ifstrequal{⟨string⟩}{⟨string⟩}{⟨true⟩}{⟨false⟩}
Compara dos cadenas y ejecuta ⟨true⟩ si son iguales y ⟨false⟩ en caso contrario. Las cadenas no se expanden en la prueba y la comparación es independiente del código de categoría. Los tokens de secuencia de control en cualquiera de los argumentos ⟨string⟩ se detokenizarán y se tratarán como cadenas. Este comando es robusto.
Por lo tanto, \ifstrequal{\testi}{...}
no devolverá verdadero a menos que ...
sea exactamente igual que\testi
como cuerdas.
Por otro lado,
\expandafter\ifstrequal\expandafter{\DDD}{2001-01-01 }{T}{F}
volverá T
, pero observe el espacio de seguimiento, que se genera al \read
ver un final de línea.
\ifx
Este es un condicional primitivo y debe usarse con su sintaxis adecuada: \ifx AB
compara los tokens A
y B
sin expansión. Entonces \ifx{\DDD}...
se comparará {
con \DDD
.
\ifcsequal
\ifcsequal{⟨csname⟩}{⟨csname⟩}{⟨true⟩}{⟨false⟩}
Similar a\ifdefequal
excepto que toma nombres de secuencias de control como argumentos.
Por lo tanto, \ifcsequal{\testi}{\DDD}
se expandirán ambos \testi
y \DDD
, por lo que es lo mismo que hacer \ifcsequal{2001-01-01}{2001-01-01 }
que devuelve falso porque las dos secuencias de control construidas son equivalentes a \relax
.
\ifdefequal
Aquí es donde finalmente obtienes que el código sea verdadero. Tenga en cuenta que si utiliza
\def\testiii{2001-\TwoDigits{\the\month}-\TwoDigits{\the\day} }%
entonces \ifdefequal{\testiii}{\DDD}
regresaráFALSO, porque solo mira la expansión del primer nivel. Por otro lado, la \edef
versión es la que funciona.
\IfStrEq
Esto amplía completamente sus argumentos (en condiciones normales), por lo que la comparación con o \testiiii
funciona \testiiii
.
Robustez
La robustez de \ifstrequal
es completamente irrelevante. Bueno, en realidad no del todo. Si su motor TeX es compatible \expanded
(todo lo será en unas pocas semanas, con el lanzamiento de TeX Live 2019), algo como
\expanded{\ifstrequal}{\testiii}{\DDD}{T}{F}}
El retorno T
y la robustez \ifstrequal
son decisivos para que esto funcione.
Utilice la prueba de trabajo.