我如何才能有效地重写这些条件?

我如何才能有效地重写这些条件?

我正在对一个用于考试和其他大学文档的旧 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应用转换。\ifthenelseifthen

我发现这个解决方案不够优雅,因为:

  • 我必须对文档的每个部分重复条件(是/否),而且语法真的很糟糕。
  • 我必须针对每个特定的切换按钮说明这一点。(目前超过 12 个)
  • 我在使用两个或更多个这样的条件时遇到了奇怪的间距问题:它们之间总是出现两个空格。
  • ifthen包裹似乎几乎过时。(检查回答)

我怎样才能使用更现代的软件包(如 etoolbox)重写它,同时抽象细节?

请注意,我主要关注的是优雅,而不是速度。我的构建速度非常快,我主要关注的是简化文档,使其更干净、更易于维护。

答案1

就我个人而言,我更愿意允许仅yes(可能不区分大小写)。我发现我可以定义一个名为的宏\showMarks来扩展为 ,这很奇怪。这似乎是一种奇怪的混合。

抛开意见不谈,ifthen它并没有过时,并且它为这样的条件提供了一个非常快速的界面,所以如果你多次进行该测试,它是一个强有力的竞争者1


不过还有其他快速选项。有etoolbox\ifboolexpr它与 类似ifthen,但提供了不同的解析机制。您可以像这样重写测试:

\ifboolexpr{%
  test {\ifstrequal{#1}{yes}}
  or
  test {\ifstrequal{#1}{si}}
  or
  ...
}

尽管您仍然需要注意不同的情况和重音(无论如何,谁用重音定义布尔选项;-)。

为了解决不同的情况,您可以使用\MakeLowercaseon \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

相关内容