5

The scenario: reading a date in a yyyy-mm-dd form from a file to a cs. This cs later gets compared to a 'current date' macro to write a few args in a specific way to an external file. The current day macro is along the lines of

% \def\TODAY{}
% \def\Today{\the\year-\TwoDigits{\the\month}-\TwoDigits{\the\day} }
\def\TODAY{\xdef\Today{\the\year-\TwoDigits{\the\month}-\TwoDigits{\the\day}}}

This works for the labeling things, since \ref{yyyy-mm-dd} works as intended. Having no extra \TODAY and then using \def'd Today does so to, it's the comparison that's not working. etoolbox's \ifstrequal is not what I used before. Whenever the date would change I used a single \xdef and later passed that macro to a \ifx, and to get it to work I had to define the date with a appended. edit Read to my amazement inserts a single space after whatever's been read.

Currently I'm supposedly fixing things, but I broke it somehow, and now it doesn't match at all. The first culprit was the my \TwoDigits cmd was robust, changing it back to \def instead of \NewDocumentCommand fixed that. The latter is for user-level commands, so I'll let that slip. But the results of the mwe are not clear to me.

0.txt contains one line with 2001-01-01 and a line new afterwards, as if one line had been written to it and the output had been closed.

The questions:

  1. What the 'right' way to compare things (macro, cs, command?) are that (should) expand to strings?
  2. Why don't \edef, \xdef work here, I thought it was a full expansion, and indeed before (my version control is nigh absent so I can't give a mwe for this) it worked.
  3. What is the significance of robustness? Is there a simple rule of thumb when it's necessary, obligatory, or irrelevant?
  4. It working with xstring's \IfStrEqual only if the is inserted in the definition of \datemacro, rather than in the comparison's brackets, i.e., {\datemacro }. Why?
  5. \ifstrequal supposedly doesn't expand- I used once in a command to test if an arguments is equal to &, this works- is #1 becoming whatever was input not count as an expansion?

edit: I forgot \ifx was used for macros, not delimited arguments, sorry.

example 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}

example 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}
  • 1
    \ifx{\testi}... compares { with \testi. Be careful with primitive TeX conditionals. – egreg Mar 11 at 7:19
4

\ifstrequal

From the documentation of etoolbox:

\ifstrequal{⟨string⟩}{⟨string⟩}{⟨true⟩}{⟨false⟩}
Compares two strings and executes ⟨true⟩ if they are equal, and ⟨false⟩ otherwise. The strings are not expanded in the test and the comparison is category code agnos- tic. Control sequence tokens in any of the ⟨string⟩ arguments will be detokenized and treated as strings. This command is robust.

Therefore \ifstrequal{\testi}{...} won't return true unless ... is exactly the same as \testi as strings.

On the other hand,

\expandafter\ifstrequal\expandafter{\DDD}{2001-01-01 }{T}{F}

will return T, but notice the traling space, which is generated by \read seeing an end-of-line.

\ifx

This is a primitive conditional and should be used with its proper syntax: \ifx AB compares the tokens A and B without expansion. So \ifx{\DDD}... will compare { with \DDD.

\ifcsequal

\ifcsequal{⟨csname⟩}{⟨csname⟩}{⟨true⟩}{⟨false⟩}
Similar to \ifdefequal except that it takes control sequence names as arguments.

Thus \ifcsequal{\testi}{\DDD} will expand both \testi and \DDD, so it is the same as doing \ifcsequal{2001-01-01}{2001-01-01 } which returns false because the two built control sequences are both equivalent to \relax.

\ifdefequal

This is where you finally get the code to return true. Note that if you use

\def\testiii{2001-\TwoDigits{\the\month}-\TwoDigits{\the\day} }%

then \ifdefequal{\testiii}{\DDD} will return false, because it just looks at the first level expansion. On the other hand, the \edef version is what works.

\IfStrEq

This does full expansion of its arguments (under normal conditions), so the comparison with either \testiiii or \testiiii works.

Robustness

The robustness of \ifstrequal is completely irrelevant. Well, not completely, actually. If your TeX engine supports \expanded (all will in a few weeks, with the release of TeX Live 2019), something like

\expanded{\ifstrequal}{\testiii}{\DDD}{T}{F}}

will return T and robustness of \ifstrequal is decisive for this to work.

Use the working test.

  • What exactly does it mean for a control sequence to be equivalent to \relax, given that \ifcsequal{\relax}{\relax}{T}{F} doesn't wants an endcsname? The robustness question is probably most important, because it's not straightforward to understand where it's important- like mentioned above, if \TwoDigits was declared viaxparse, it doesn't work in my code, cannot guarantee for the 2. given example. – vlg Mar 11 at 8:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.