场景: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
,我以为这是一个完整的扩展,事实上之前(我的版本控制几乎没有,所以我不能给出一个mwe)它起作用了。 - 稳健性的意义何在?当它是必要的、强制性的或不相关的时,是否有一个简单的经验法则?
xstring
它与\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
,所以它与执行返回 false 的操作相同,\ifcsequal{2001-01-01}{2001-01-01 }
因为两个构建的控制序列都等同于\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
对于其工作起着决定性的作用。
使用工作测试。