我正在对一个用于考试和其他大学文档的旧 LuaLaTeX 模板进行现代化改造和改编。问题是,该文档充满了如下条件:
\newcommand{\showMarks}{Yes} % This is where the user is supposed to toggle marks
% ... later in the document ...
\ifthenelse{
\equal{\showMarks}{Yes} \OR \equal{\showMarks}{yes} \OR \equal{\showMarks}{Si}
\OR{} \equal{\mostrarPuntos}{Sí} \OR{} \equal{\mostrarPuntos}{si} % and so on
}
{\pointformat{\bfseries(\themarginpoints)}} % if
{\pointformat{}} % else
(请注意,我使用了多个 OR,因为它需要处理西班牙语和英语)
如您所见,模板用于定义切换,然后使用(来自包)\newcommand
应用转换。\ifthenelse
ifthen
我发现这个解决方案不够优雅,因为:
- 我必须对文档的每个部分重复条件(是/否),而且语法真的很糟糕。
- 我必须针对每个特定的切换按钮说明这一点。(目前超过 12 个)
- 我在使用两个或更多个这样的条件时遇到了奇怪的间距问题:它们之间总是出现两个空格。
- 该
ifthen
包裹似乎几乎过时。(检查这回答)
我怎样才能使用更现代的软件包(如 etoolbox)重写它,同时抽象细节?
请注意,我主要关注的是优雅,而不是速度。我的构建速度非常快,我主要关注的是简化文档,使其更干净、更易于维护。
答案1
就我个人而言,我更愿意允许仅yes
(可能不区分大小写)。我发现我可以定义一个名为的宏\showMarks
来扩展为 ,这很奇怪sí
。这似乎是一种奇怪的混合。
抛开意见不谈,ifthen
它并没有过时,并且它为这样的条件提供了一个非常快速的界面,所以如果你多次进行该测试,它是一个强有力的竞争者1。
不过还有其他快速选项。有etoolbox
,\ifboolexpr
它与 类似ifthen
,但提供了不同的解析机制。您可以像这样重写测试:
\ifboolexpr{%
test {\ifstrequal{#1}{yes}}
or
test {\ifstrequal{#1}{si}}
or
...
}
尽管您仍然需要注意不同的情况和重音(无论如何,谁用重音定义布尔选项;-)。
为了解决不同的情况,您可以使用\MakeLowercase
on \showMarks
,然后与小写版本进行比较,这样您就可以得到简短的结果:
\ifboolexpr{%
test {\ifstrequal{#1}{yes}}
or
test {\ifstrequal{#1}{si}}
or
test {\ifstrequal{#1}{s\IeC{\'\i}}}
or
test {\ifstrequal{#1}{s\IeC{\'i}}}% For SÍ
}
虽然可能不会比这短太多。这是最快的(在之后ifhten
)选项,因为大小写转换使用了 TeX 的\lowercase
。下面的 MWE #1 实现了这个版本。
如果您更喜欢不太冗长的语法,您可以尝试expl3
's \str_case:nn
(感谢 Henri 提醒我这一点 :-)。您可以使用\str_case:nnTF
并向其传递一个字符串列表,以便它进行检查,然后如果有任何测试匹配,则相应地进行分支。此外,由于expl3
's 的大小写转换,测试变得非常简短:
\str_case:nnTF {#1}
{
{yes} { }
{si} { }
{sí} { }
}
{ \prg_return_true: }
{ \prg_return_false: }
此外,由于大小写转换和字符串测试在 中都是可扩展的expl3
,因此您可以将整个内容编写为可扩展测试。下面的 MWE #2 实现了这一点。此版本中的条件比前一个版本简单得多,因此速度要快得多,但整个代码可能会慢一点,因为大小写转换使用基于宏的方法,而不是\lowercase
。但大小写转换要好得多,因为它“只适用于”Unicode 字符,例如í
。
如果您想要最短的代码,可以使用l3regex
。我怀疑还有比这更短的代码。您只需定义一个正则表达式,例如:
\regex_const:Nn \c_augustin_yes_regex { (?i)^yes|s(i|í|Í)$ }
然后使用 进行测试\regex_match:NnTF
。但是,由于这确实很多不仅仅是比较字符串,这比其他选项要慢(我说的慢是指你必须运行测试数千次才能注意到),但是如果你想让你的测试变得非常花哨,这可以让你进行很多扩展。MWE #3 实现了这一点。
最大能量损失 #1
\documentclass{article}
\usepackage{etoolbox}
\newrobustcmd\IfShowMarksTF{%
\MakeLowercase{\gdef\noexpand\showmarkstest{\showMarks}}%
\expandafter\ifshowmarksaux
\expandafter{\showmarkstest}}%
\newrobustcmd\ifshowmarksaux[1]{%
\ifboolexpr{%
test {\ifstrequal{#1}{yes}}
or
test {\ifstrequal{#1}{si}}
or
test {\ifstrequal{#1}{s\IeC{\'\i}}}
or
test {\ifstrequal{#1}{s\IeC{\'i}}}% For SÍ
}}
\ExplSyntaxOff
\begin{document}
\def\test#1{%
\def\showMarks{#1}%
#1: \IfShowMarksTF{true}{false}\par}
\test{yes}
\test{Yes}
\test{YES}
\test{yEs}
\test{si}
\test{SI}
\test{Sí}
\test{sÍ}
\test{no}
\test{sim}
\end{document}
最大能量损失 #2
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewExpandableDocumentCommand \IfShowMarksTF { m m }
{
\exp_args:Ne \augustin_if_yes:nTF
{ \text_lowercase:n { \showMarks } }
{#1} {#2}
}
\prg_new_conditional:Npnn \augustin_if_yes:n #1 { p, T, F, TF }
{
\str_case:nnTF {#1}
{
{yes} { }
{si} { }
{sí} { }
}
{ \prg_return_true: }
{ \prg_return_false: }
}
\ExplSyntaxOff
\begin{document}
\def\test#1{%
\def\showMarks{#1}%
#1: \IfShowMarksTF{true}{false}\par}
\test{yes}
\test{Yes}
\test{YES}
\test{yEs}
\test{si}
\test{SI}
\test{Sí}
\test{sÍ}
\test{no}
\test{sim}
\end{document}
重金属污染指数#3
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\regex_const:Nn \c_augustin_yes_regex { (?i)^yes|s(i|í|Í)$ }
\NewDocumentCommand \IfShowMarksTF { m m }
{
\exp_args:NNV \regex_match:NnTF
\c_augustin_yes_regex \showMarks
{#1} {#2}
}
\ExplSyntaxOff
\begin{document}
\def\test#1{%
\def\showMarks{#1}%
#1: \IfShowMarksTF{true}{false}\par}
\test{yes}
\test{Yes}
\test{YES}
\test{yEs}
\test{si}
\test{SI}
\test{Sí}
\test{sÍ}
\test{no}
\test{sim}
\end{document}
所有测试文件打印:
1但是,如果您多次进行该测试,最好只测试一次,然后以某种方式存储测试结果,例如:
\newif\ifshowmarks
\ifthenelse{<many tests>}%
{\showmarkstrue}%
{\showmarksfalse}%
% then
\ifshowmarks
<do stuff>
\else
<other stuff>
\fi