17

This must be a LateX 101 question, so I ask for your kindness

I want to make a choice based on the value of a theorem counter.

I use the xifthen package (especially the \isin function, which tests if a first string is a part of a second string) and the following function:

\newcommand{\test}[2]{\ifthenelse{\isin{|#1|}{#2}}{Yes}{No}}

For example:

\test{17}{|15|17|19|} returns Yes

\test{18}{|15|17|19|} returns No

But how to replace the first argument of \test by the current value of a counter?

0

5 Answers 5

9

Or use package xstring, which has all manner of neat tests built in:

\documentclass{article}

\usepackage{xstring}

\newcounter{sausage}
\setcounter{sausage}{18}

\begin{document}

\IfSubStr{|17|18|19|}{|\arabic{sausage}|}{true}{false}
\IfSubStr{|17|15|19|}{|\arabic{sausage}|}{true}{false}

\end{document}
1
  • 1
    \IfSubStr{17|118|19} {\arabic{sausage}}{true}{false} yields true, which does not to seem to match the OP's request. You should write something like \IfSubStr{|17|118|19|} {|\arabic{sausage}|}{true}{false} instead. Nov 9, 2016 at 8:47
12
\documentclass{article}
\usepackage{xifthen}
\newcounter{mycounter}
\setcounter{mycounter}{17}
\newcommand{\test}[2]{\ifthenelse{\isin{|#1|}{#2}}{Yes}{No}}
\begin{document}
\test{17}{|15|17|19|} returns Yes

\test{18}{|15|17|19|} returns No

\edef\tmp{\themycounter}
\expandafter\test\expandafter{\tmp}{|15|17|19|} returns Yes
\end{document}

This approach can be directly incorporated into the macro:

\documentclass{article}
\usepackage{xifthen}
\newcounter{mycounter}
\setcounter{mycounter}{17}
\newcommand{\test}[2]{%
  \edef\tmp{#1}%
  \ifthenelse{\expandafter\isin\expandafter{\expandafter|\tmp|}{#2}}{Yes}{No}%
}
\begin{document}
\test{17}{|15|17|19|} returns Yes

\test{18}{|15|17|19|} returns No

\test{\themycounter}{|15|17|19|} returns Yes
\end{document}

And for a completely different approach, here I use the listofitems package to parse argument #2 using expanded argument |#1| as the separator. If I get more than 1 element in the resulting array list, then one may conclude that the separator was found in #2.

\documentclass{article}
\usepackage{listofitems}
\newcounter{mycounter}
\newcommand{\test}[2]{%
  \edef\tmp{#1}%
  \expandafter\setsepchar\expandafter{\expandafter{\expandafter|\tmp|}}%
  \readlist\tmparray{#2}
  \ifnum\tmparraylen>1\relax Yes\else No\fi%
}
\begin{document}
\test{17}{|15|17|19|} returns Yes

\test{18}{|15|17|19|} returns No

\setcounter{mycounter}{17}
\test{\themycounter}{|15|17|19|} returns Yes
\end{document}
10

You can use pdfTeX's \pdfmatch{<strA>}{<strB>} which returns 1 if <strA> is found in <strB>. Pattern matching with punctuation requires some care. This is expandable:

enter image description here

\documentclass{article}

\newcommand{\test}[2]{\ifnum\pdfmatch{[|]#1[|]}{#2}=1 Yes\else No\fi}

\begin{document}

\verb!\test{17}{|15|17|19|}! returns: \test{17}{|15|17|19|}

\verb!\test{18}{|15|17|19|}! returns: \test{18}{|15|17|19|}

\newcounter{test}

\setcounter{test}{17}%
\verb!\test{\thetest}{|15|17|19|}! returns: \test{\thetest}{|15|17|19|}

\setcounter{test}{18}%
\verb!\test{\thetest}{|15|17|19|}! returns: \test{\thetest}{|15|17|19|}

\end{document}

The above pattern matching for \thetest works because \thetest expands to \arabic{test} (by default). If this is not the case, you can use \arabic{test} directly.

8

You can use \int_case:nnF of expl3.

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\test}{m}
 {
  \int_case:nnF { #1 }
   {
    {15}{Yes}
    {17}{Yes,~it's~17}
    {19}{Yes,~but~it's~big}
   }
   {No}
 }
\ExplSyntaxOff

\newcommand{\fifteen}{15}
\newcounter{test}

\begin{document}

\test{17}

\test{\fifteen}

\setcounter{test}{19}
\test{\value{test}}

\setcounter{test}{42}
\test{\value{test}}

\test{43}

\end{document}

enter image description here

If you just want to do a yes/no comparison with a list of integers, you can do

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\test}{m}
 {
  \bool_if:nTF
   {
    \int_compare_p:n { #1 = 15 }
    ||
    \int_compare_p:n { #1 = 17 }
    ||
    \int_compare_p:n { #1 = 19 }
   }
   {Yes}
   {No}
 }
\ExplSyntaxOff

\newcommand{\fifteen}{15}
\newcounter{test}

\begin{document}

\test{17}

\test{\fifteen}

\setcounter{test}{19}
\test{\value{test}}

\setcounter{test}{42}
\test{\value{test}}

\test{43}

\end{document}

An extended version with three possible choices. The first does not accept the second argument in the form of alternatives, but is fully expandable; the second and the third versions accept the second argument, but only the latter is fully expandable.

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\DeclareExpandableDocumentCommand{\testA}{m}
 {
  \bool_if:nTF
   {
    \int_compare_p:n { #1 = 15 }
    ||
    \int_compare_p:n { #1 = 17 }
    ||
    \int_compare_p:n { #1 = 19 }
   }
   {Yes}
   {No}
 }

\NewDocumentCommand{\testB}{mm}
 {
  \seq_set_split:Nnn \l_tmpa_seq { | } { #2 }
  \seq_if_in:NfTF \l_tmpa_seq { \int_eval:n { #1 } }
   {Yes}
   {No}
 }
\cs_generate_variant:Nn \seq_if_in:NnTF { Nf }

\DeclareExpandableDocumentCommand{\testC}{mm}
 {
  \ferrard_test:fn { \int_eval:n { #1 } } { #2 }
 }

\cs_new:Nn \ferrard_test:nn
 {
  \ferrard_test_aux:nw { #1 } #2 | \q_stop
 }
\cs_new:Npn \ferrard_test_aux:nw #1 #2 | #3 \q_stop
 {
  \tl_if_empty:nTF { #2 }
   {No}
   {
    \int_compare:nTF { #1 = #2 }
     {Yes}
     { \ferrard_test_aux:nw { #1 } #3 | \q_stop }
   }
 }
\cs_generate_variant:Nn \ferrard_test:nn { f }
\ExplSyntaxOff

\newcommand{\fifteen}{15}
\newcounter{test}

\begin{document}

\section{Test A}

\testA{17}

\testA{\fifteen}

\setcounter{test}{19}
\testA{\value{test}}

\setcounter{test}{42}
\testA{\value{test}}

\testA{43}

\section{Test B}

\testB{17}{15|17|19}

\testB{\fifteen}{15|17|19}

\setcounter{test}{19}
\testB{\value{test}}{15|17|19}

\setcounter{test}{42}
\testB{\value{test}}{15|17|19}

\testB{43}{15|17|19}

\section{Test C}

\testC{17}{15|17|19}

\testC{\fifteen}{15|17|19}

\setcounter{test}{19}
\testC{\value{test}}{15|17|19}

\setcounter{test}{42}
\testC{\value{test}}{15|17|19}

\testC{43}{15|17|19}

\end{document}

enter image description here

0
0

A no package, easily extendable approach.

I used \numexpr only for allowing expressions in input. And I use \detokenize only for displaying input. Else, these e-TeX extensions are not needed.

\documentclass{article}

\makeatletter
% borrowed from xintkernel.sty
\long\def\dothis #1#2\orthat #3{\fi #1}%
\let\orthat \@firstofone
\makeatother

\newcommand*{\test}[1]{The test of \texttt{\detokenize{#1}} gives:
  \ifnum\numexpr#1=15 \dothis{Yes (15)}\fi
  \ifnum\numexpr#1=17 \dothis{Yes (17)}\fi
  \ifnum\numexpr#1=19 \dothis{Yes (19)}\fi
  \orthat{NO!}%
}%

\newcommand{\fifteen}{15}

\newcounter{mycounter}

\begin{document}

\test{17}

\test{\fifteen}

\setcounter{mycounter}{19}
\test{\value{mycounter}}

\setcounter{mycounter}{42}
\test{\value{mycounter}}

\test{43}

\test{11+4+4}

\end{document}

enter image description here

Here I do not handle presenting the set of allowed values in the form |15|17|19| but macros can be of course produced for that. And with , as separator, then this is ready-made (expandably) via xinttools utilities (or LaTeX3 of course).

In the \dothis/\orthat approach (copied over from xintkernel.sty) the conditions are tested and as soon as one is positive the corresponding \dothis code executes, and then all left-over tests are skipped. If all such tests fail, it is the \orthat code that executes. This (all the \ifnum tests ending in \orthat{FOO}) is expandable code, of course. Here I added to \test macro extra stuff to better display results in mwe.

If the question is only to test if given input is in given list then old-timers method of \if1\ifnum .... etc... allow to put together many \ifnum without complicated \expandafter or \fi\fi...\fi.

But here I saw other answers handling separate code outputs according to input so I did the same.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .