Сценарий: чтение даты в yyyy-mm-dd
форме из файла в cs. Этот cs позже сравнивается с макросом «текущая дата», чтобы записать несколько аргументов определенным образом во внешний файл. Макрос текущего дня похож на
% \def\TODAY{}
% \def\Today{\the\year-\TwoDigits{\the\month}-\TwoDigits{\the\day} }
\def\TODAY{\xdef\Today{\the\year-\TwoDigits{\the\month}-\TwoDigits{\the\day}}}
Это работает для маркировки вещей, так как \ref{yyyy-mm-dd}
работает так, как и предполагалось. Не имея дополнительных \TODAY
и затем используя \def
'd Today, это делает то, что не работает, это сравнение. etoolbox
's \ifstrequal
- это не то, что я использовал раньше. Всякий раз, когда дата менялась, я использовал один \xdef
и позже передавал этот макрос в \ifx
, и чтобы заставить его работать, мне приходилось определять дату с добавленным.редактироватьПрочитанное к моему изумлению вставляет один пробел после всего прочитанного.
В настоящее время я, как предполагается, что-то чиню, но я как-то сломал его, и теперь он вообще не совпадает. Первым виновником был мой \TwoDigits
cmd, который был устойчив, и я изменил его обратно на \def
вместо того, чтобы \NewDocumentCommand
исправить это. Последнее относится к командам уровня пользователя, так что я промолчу об этом. Но результаты mwe мне не ясны.
0.txt
содержит одну строку 2001-01-01
и одну новую строку после нее, как будто в нее была записана одна строка, а вывод был закрыт.
Вопросы:
- Каков «правильный» способ сравнения вещей (макросов, CS, команд?), которые (должны) расширяться до строк?
- Почему бы и нет
\edef
,\xdef
поработайте здесь, я думал, что это полноценное расширение, и действительно, раньше (у меня почти нет системы контроля версий, так что я не могу сказать, что это такое) это работало. - В чем значение надежности? Есть ли простое правило, когда это необходимо, обязательно или неактуально?
- Он работает с
xstring
's\IfStrEqual
толькоесливставлено в определение
\datemacro
, а не в скобки сравнения, т.е.{\datemacro }
. Почему? \ifstrequal
предположительно не расширяется - я использовал один раз в команде, чтобы проверить, равен ли аргумент&
, это работает - становится ли #1 тем, что было введено, не считается расширением?
редактировать: Я забыл, \ifx
что используется для макросов, а не для разделенных аргументов, извините.
пример 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}
пример 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
\ifstrequal
Из документации etoolbox
:
\ifstrequal{⟨string⟩}{⟨string⟩}{⟨true⟩}{⟨false⟩}
Сравнивает две строки и выполняет ⟨true⟩, если они равны, и ⟨false⟩ в противном случае. Строки не расширяются в тесте, и сравнение не зависит от кода категории. Токены управляющей последовательности в любом из аргументов ⟨string⟩ будут детокенизированы и обработаны как строки. Эта команда надежна.
Поэтому \ifstrequal{\testi}{...}
не вернет true, если только не ...
будет точно таким же, как\testi
как струны.
С другой стороны,
\expandafter\ifstrequal\expandafter{\DDD}{2001-01-01 }{T}{F}
вернет T
, но обратите внимание на завершающий пробел, который образуется при \read
появлении конца строки.
\ifx
Это примитивное условное выражение, и его следует использовать с его правильным синтаксисом: \ifx AB
сравнивает токены A
и B
без расширения. Поэтому \ifx{\DDD}...
будет сравнивать {
с \DDD
.
\ifcsequal
\ifcsequal{⟨csname⟩}{⟨csname⟩}{⟨true⟩}{⟨false⟩}
Аналогично , за\ifdefequal
исключением того, что в качестве аргументов он принимает имена управляющих последовательностей.
Таким образом \ifcsequal{\testi}{\DDD}
будут расширены \testi
и \DDD
, так что это то же самое, что и выполнение \ifcsequal{2001-01-01}{2001-01-01 }
, которое возвращает false, поскольку обе построенные управляющие последовательности эквивалентны \relax
.
\ifdefequal
Здесь вы наконец-то получаете код, который возвращает true. Обратите внимание, что если вы используете
\def\testiii{2001-\TwoDigits{\the\month}-\TwoDigits{\the\day} }%
затем \ifdefequal{\testiii}{\DDD}
вернетсяЛОЖЬ, потому что он просто смотрит на расширение первого уровня. С другой стороны, версия \edef
— это то, что работает.
\IfStrEq
Это делает полное расширение его аргументов (при нормальных условиях), поэтому сравнение с или \testiiii
работает \testiiii
.
Надежность
Надежность \ifstrequal
совершенно не важна. Ну, не совсем, на самом деле. Если ваш движок TeX поддерживает \expanded
(все будут через несколько недель, с выходом TeX Live 2019), что-то вроде
\expanded{\ifstrequal}{\testiii}{\DDD}{T}{F}}
вернется T
, и надежность \ifstrequal
имеет решающее значение для его работы.
Используйте рабочий тест.