将多个条件放在一个序列中

将多个条件放在一个序列中

我经常需要做这样的事情:

IF x < 1, DO a
ELSE IF x < 2, DO b
ELSE IF x < 3, DO c
ELSE, DO d

使用etoolbox,我最终嵌套了很多ifnumless,如下所示:

\ifnumless{x}{1}{a}{
    \ifnumless{x}{2}{b}{
        \ifnumless{x}{3}{c}{
            d
        }
    }
}

有没有更简单的方法来实现这一点?

答案1

一种“switchcase”可以很容易地编程:

\documentclass{article}
\makeatletter
\def\ifnumcase#1{%
    \edef\elseif@{\string\elseif}\edef\endif@{\string\endif}%
    \def\number@test{#1pt}\ifnumcase@i}
\def\ifnumcase@i#1{%
    \def\ifnumcase@ii##1{%
        \csname
            @\ifdim\number@test#1pt first\else second\fi oftwo%
        \endcsname{##1\gobto@endif}\ifnumcase@i}%
    \edef\valeur@{\string#1}%
    \csname
        \ifx\valeur@\elseif@ idto@endif%
        \else\ifx\valeur@\endif@ relax\else ifnumcase@ii\fi
        \fi
    \endcsname}
\def\idto@endif#1\endif{#1}
\def\gobto@endif#1\endif{}
\makeatother
\begin{document}
\ifnumcase{7.5}% <- number to test
    {<1}{less than 1}
    {<3}{less than 3}
    {>5}{greater than 5}
    % add other tests if needed
\elseif
    between 3 and 5% all tests faild
\endif

\ifnumcase{3.14}% <- number to test
    {<2}{less than 1}
    {<3}{less than 3}
    {<4}{less than 4}
    {<10}{less than 10}
    % add possible other tests
\endif
\end{document}

编辑:使用=、、或测试的更完整和可扩展的解决方案:<><=<=

\documentclass{article}
\usepackage[T1]{fontenc}
\makeatletter
\def\elseif{\elseif}\def\endif{\endif}
\def\ifnumcase#1#2{%
    \expandafter\ifx\expandafter\elseif\@car#2\@nil\expandafter\@firstoftwo
    \else
        \expandafter\ifx\expandafter\endif\@car#2\@nil\expandafter\expandafter\expandafter\@gobbletwo
        \else\expandafter\expandafter\expandafter\@secondoftwo
        \fi
    \fi
        \idto@endif
        {\if@eqin#2=\@nil{\if@dimwitheq{#1}#2\@nil}{\ifdim#1pt#2pt }
            \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi\exec@arg{\ifnumcase@i{#1}}%
        }%
    }
\def\ifnumcase@i#1#2{\ifnumcase{#1}}
\def\if@eqin#1=#2\@nil{%
    \ifx\@empty#2\@empty\expandafter\@secondoftwo
    \else
        \ifx\@empty#1\@empty\expandafter\expandafter\expandafter\@secondoftwo
        \else\expandafter\expandafter\expandafter\@firstoftwo
        \fi
    \fi}
\def\if@dimwitheq#1#2=#3\@nil{\unless\ifdim#1pt\if<#2>\else<\fi#3pt }
\def\exec@arg#1#2\endif{#1}
\def\idto@endif#1\endif{#1}
\def\gobto@endif#1\endif{}
\makeatother
\begin{document}
\ifnumcase{3}
    {<=1}{lt or equal 1}
    {>=3}{gt or equal 3}
\elseif
    beteween 1 and 3
\endif

\ifnumcase{4}% <- number to test
    {<=1}{less or equal 1}
    {<=3}{less or equal 3}
    {=4}{equal 4}
    {>=5}{greater or equal 5}
    % add other tests if needed
\elseif
    between 3 and 5% all tests faild
\endif

\edef\foo{\ifnumcase{5}% <- number to test
    {<=1}{less or equal 1}
    {<=3}{less or equal 3}
    {=4}{equal 4}
    {>=5}{greater or equal 5}
    % add other tests if needed
\elseif
    between 3 and 5% all tests faild
\endif}\meaning\foo

\ifnumcase{3.14}% <- number to test
    {<2}{less than 1}
    {<3}{less than 3}
    {<4}{less than 4}
    {<10}{less than 10}
    % add possible other tests
\endif
\end{document}

答案2

根据还有谁需要使用代码,lualatex 是否可以工作?

\documentclass{article}
\begin{document}
\directlua{
x=1.5
}
\directlua{
if x<1 then
  tex.print('a')
elseif x<2 then
  tex.print('b')
elseif x<3 then
  tex.print('c')
else
  tex.print('d')
end
}
\end{document}

答案3

如果仅将其与整数进行比较,那么很容易:

\documentclass{minimal}   
\def\getInteger#1{\expandafter\stripDecimals#1..!!}
\def\stripDecimals#1.#2.#3!!{\ifx\relax#1\relax0\else#1\fi}

\def\x{\getInteger{0.5}}      
\begin{document}   

\ifcase\x   % 0
 lt 1\or    % 1
 lt 2\or    % 2
 lt 3       % 3
\else gt 3  % else
\fi

\end{document}

答案4

一个可扩展且更完整的“切换”解决方案是:

\documentclass{article}
\makeatletter
\def\identoendif#1\endif{#1}
\def\oneoftoendif#1#2\endif{#1}
\def\gobbletoendif#1\endif{}
\newcommand*\ifstrsame[2]{%
  \@nameuse{@\ifnum\pdfstrcmp{\detokenize{#1}}%
    {\detokenize{#2}}=0first\else second\fi oftwo}%
}
\def\dimexpr@i#1{#1\dimexpr}
\def\ifnumcase#1{%
  \ifstrsame{#1}\elseif\gobbletoendif{%
    \ifstrsame{#1}\endif\@gobble\ifnumcase@i
  }{#1}%
}
\def\ifnumcase@i#1#2{%
  \ifstrsame{#2}\elseif\identoendif{%
    \ifstrsame{#2}\endif{}{%
      \ifdim\dimexpr#1pt\relax\dimexpr@i#2pt\relax
        \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
          {\oneoftoendif}{\ifnumcase@ii{#1}}%
    }%
  }%
}
\def\ifnumcase@ii#1#2#3{\ifnumcase@i{#1}{#3}}
\makeatother

%% Examples:
\edef\x{%
  \ifnumcase{6}% <- number to test
    {<1}{less than 1}
    {<3}{less than 3}
    {>5}{greater than 5}
    % add other tests if needed
  \elseif
    between 3 and 5% all tests failed
  \endif
}
\show\x -> greater than 5

\edef\x{%
  \ifnumcase{3.14}% <- number to test
    {<2}{less than 1}
    {<3}{less than 3}
    {<4}{less than 4}
    {<10}{less than 10}
    % add possible other tests
  \endif
}
\show\x -> less than 4

\edef\x{%
  \ifnumcase{314}% <- number to test
    {<2}{less than 1}
    {<3}{less than 3}
    {<4}{less than 4}
    {<10}{less than 10}
    % add possible other tests
  \endif
}
\show\x -> empty

\begin{document}
% Nothing to do:
\ifnumcase\elseif\endif
\ifnumcase{3}\elseif\endif
\ifnumcase\endif
\ifnumcase{3}\endif
\end{document}

unbonpetit 的最新解决方案失败了

\ifnumcasse{3}
    {=<1}{lt or equal 1}
    {=>3}{gt or equal 3}
\elseif
    beteween 1 and 3
\endif

\def\gobto@endif#1\endif{}

是多余的。

更通用的解决方案是

\makeatletter
\def\elseif{\@gobble\elseif}
\def\endif{\@gobble\endif}
\def\swap#1#2{#2#1}
\def\ifstrsame#1#2{%
  \ifnum\pdfstrcmp{\detokenize{#1}}{\detokenize{#2}}=\z@
  \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}
\def\ifstrnull#1{%
  \ifnum\pdfstrcmp{\detokenize{#1}}{}=\z@
  \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}
\def\ifcmdeq#1#2{%
  \ifx#1#2\endif\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}
\def\if@eqin#1=#2\@nil{%
  \ifstrnull{#2}\@secondoftwo{\ifstrnull{#1}\@secondoftwo\@firstoftwo}%
}
\def\if@dimwitheq#1#2=#3\@nil{\unless\ifdim#1pt\if<#2>\else<\fi#3pt }
\def\docasecallback#1#2\endif{#1}
\def\doelsepart#1\endif{#1}
\def\ifnumcase#1#2{%
  \expandafter\ifcmdeq\@car#2\@nil\elseif\@firstoftwo{%
    \expandafter\ifcmdeq\@car#2\@nil\endif\@gobbletwo\@secondoftwo
  }%
  \doelsepart{%
    \expandafter\expandafter\expandafter
    \if@eqin\checkcomparators#2\@nil=\@nil{%
      \expandafter\expandafter\expandafter\swap
      \expandafter\expandafter\expandafter
      {\checkcomparators#2\@nil}{\if@dimwitheq{#1}}\@nil
    }{%
      \ifdim#1pt#2pt %
    }
    \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
    \docasecallback{\ifnumcase@i{#1}}%
  }%
}
\def\ifnumcase@i#1#2{\ifnumcase{#1}}
\def\checkcomparators#1#2#3\@nil{%
  \romannumeral
  \ifstrsame{#1}={\ifstrsame{#2}<{0<=#3}{\ifstrsame{#2}>{0>=#3}{0 #1#2#3}}%
  }{0 #1#2#3}%
}
\makeatother

相关内容