5

I'm working on a document command that has a variety of optional arguments for different results. I need to add an option that yields 'true' for an optional argument within a range of numbers, for example 100-200. The command is as follows (MWE):

\documentclass{article}
\usepackage{xparse,xstring,xspace}

\NewDocumentCommand{\Foo}{ o }{%
    \IfNoValueTF{#1} {%
    \emph{Foo}\xspace}{%
        \IfBeginWith{#1}%
        {b}{\emph{Foo} Bar\xspace}{%
            \IfStrEqCase{#1}{%
                {f}{\emph{Foo}\xspace}%
                }%
                [\emph{Foo}~#1\xspace]%
            }%
        }%
    }

\begin{document}

\Foo

\Foo[b]

\Foo[3]

\end{document}

xstring does not appear to have a range option.

egreg
  • 1,121,712
DavidR
  • 1,107
  • If you know the argument to be a number, would it not be easier to put the number into a counter, and test the counter within a range? After all, xstring works with strings, not numbers. – Steven B. Segletes Feb 11 '14 at 14:38
  • Could you be more specific about the allowed values? – egreg Feb 11 '14 at 14:41
  • Steven: the argument can also be a letter (b).

    egreg: actually, in my specific case it just has to be above 343 rather than in a range, but I wanted to make the question more general/applicable.

    – DavidR Feb 11 '14 at 14:44
  • So, if the optional argument starts with b something should be done, otherwise it should be a number and this number should be examined? – egreg Feb 11 '14 at 14:49
  • Use @steven B. Segletes to direct your comment to my attention, FYI. The "at" sign is important. – Steven B. Segletes Feb 11 '14 at 14:50
  • @egreg the optional argument is either a letter or a number. If its a number, then is it in the range 343+: if so do this, if not do that. – DavidR Feb 11 '14 at 14:57

3 Answers3

5
\documentclass{minimal}
\usepackage{xspace}
\newcommand\isnum[3]{%
  \if!\ifnum9<1#1!\else_\fi       % a number or something else?
    \ifnum#1>99\relax             % we have a number > 99
      \ifnum#1<201\relax #2       % it is in [100;200]
      \else #3\fi         % not a number or not in [100;200]
    \else #3\fi
  \else #3\fi\xspace}
\newcommand\Foo[1][a]{\isnum{#1}{true}{false}}

\begin{document}

\Foo, \Foo[b], \Foo[3], \Foo[155]

\end{document}

enter image description here

5

My proposal is to test the first token in the optional argument; if it's a digit, we assume it's a number:

\documentclass{article}
\usepackage{xparse,xspace}

\ExplSyntaxOn
\NewDocumentCommand{\foo}{ o }
 {
  \IfNoValueTF{#1}
   {
    \emph{Foo}\xspace
   }
   {
    \rowthorn_check_arg:n { #1 }
   }
 }
\cs_new_protected:Npn \rowthorn_check_arg:n #1
 {
  \tl_if_in:nfTF {0123456789} { \tl_head:n { #1 } }
   {
    \rowthorn_numeric_arg:n { #1 }
   }
   {
    \rowthorn_string_arg:n { #1 }
   }
 }
\cs_generate_variant:Nn \tl_if_in:nnTF { nf }
\cs_new_protected:Npn \rowthorn_numeric_arg:n #1
 {
  \int_compare:nTF { #1 > 343 }
   {
    \emph{Foo}~(#1)
   }
   {
    \emph{Foo}
   }
 }
\cs_new_protected:Npn \rowthorn_string_arg:n #1
 {
  \emph{Foo}~[#1]
 }

\ExplSyntaxOff

\begin{document}
\foo test

\foo[bxx] test

\foo[f] test

\foo[fx] test

\foo[3] test

\foo[400] test
\end{document}

It's up to you completing the specification.

enter image description here

egreg
  • 1,121,712
4

Here is the xstring version:

enter image description here

Notes:

Code:

\documentclass{article}
\usepackage{xstring}
\usepackage{pgf}

% https://tex.stackexchange.com/questions/50111/how-to-check-if-the-value-of-a-parameter-is-a-number \newcommand*{\IsInteger}[3]{% \IfStrEq{#1}{ }{% #3% is a blank string }{% \IfInteger{#1}{#2}{#3}% }% }%

% https://tex.stackexchange.com/questions/15297/how-to-test-if-a-number-is-negative \newcommand{\IsZeroOrPositive}[3]{% % #1 = number to test % #2 = code to executer if positive % #3 = code to execute if non-postiive \pgfmathsetmacro{\varX}{#1}% \pgfmathparse{ifthenelse(\varX>=0,1,0)}% \if\pgfmathresult 1 \relax% #2% \else% #3% \fi% }%

\newcommand{\RangeMin}{100}% \newcommand{\RangeMax}{200}% \newcommand*{\IsInRange}[3]{% % #1 = number to test % #2 = code to execute if in range % #3 = code to execute if NOT in range, or #1 NOT an integer \IsInteger{#1}{% \IsZeroOrPositive{#1-\RangeMin}{% \IsZeroOrPositive{\RangeMax-#1}{% #2% Number is in range }{% #3% Number not in range }% }{% #3% Number not in range }% }{% #3% Not a number }% }

\begin{document} Character ``a" is \IsInRange{a}{in range}{not in range}.\par Empty string is \IsInRange{}{in range}{not in range}.\par Blank string is \IsInRange{ }{in range}{not in range}.\par

\medskip 2 is \IsInRange{2}{in range}{not in range}.\par 99 is \IsInRange{99}{in range}{not in range}.\par 100 is \IsInRange{100}{in range}{not in range}.\par 111 is \IsInRange{111}{in range}{not in range}.\par 200 is \IsInRange{200}{in range}{not in range}.\par 201 is \IsInRange{201}{in range}{not in range}. \end{document}

Peter Grill
  • 223,288