9

I am looking for a command allowing me to get 3 as output if the input is 3.2. \StrBefore{3.2}{.} works fine for this purpose but is not expandable and I need to call it in another macro inside a \setcounter command where it is expected to have a number and then to expand the \StrBefore command. Is there a work around using \StrBefore or do I need a different function and which one?

\documentclass{book}

\usepackage{xstring}

\newcounter{try}

\newcommand{\foo}[1]{\StrBefore{#1}{.}}

\newcommand\test[1]{\setcounter{try}{\foo{#1}}%
\arabic{try}}

\begin{document}

Result of foo\{3.2\}: \foo{3.2}
Result of test\{3.2\}: \test{3.2}

\end{document}
Ludovic C.
  • 8,888

3 Answers3

12

One approach is using the optional argument of StrBefore:

\documentclass{book}
\usepackage{xstring}
\usepackage{ifthen}

\newcounter{try}

\newcommand{\foo}[1]{\StrBefore{#1}{.}[\result]}

\newcommand\test[1]{\foo{#1}\setcounter{try}{\result}\arabic{try}}%


\begin{document}

Result of foo\{3.2\}: \foo{3.2}
Result of test\{3.2\}: \test{3.2}

\end{document}
Marco Daniel
  • 95,681
10

Another approach would be to parse it yourself, without needing any assignments (except in the preamble to define \foo and a helper macro):

\documentclass{book}

%\usepackage{xstring}
%\newcommand{\foo}[1]{\StrBefore{#1}{.}}

\makeatletter
\def\fooex#1.#2\@nil{#1}
\newcommand{\foo}[1]{\fooex #1.\@nil}
\makeatother

\newcounter{try}
\newcommand\test[1]{\setcounter{try}{\foo{#1}}%
\arabic{try}}

\begin{document}

Result of foo\{3.2\}: \foo{3.2},
Result of foo\{32\}: \foo{32},

Result of test\{3.2\}: \test{3.2}

\end{document}

Updated using suggestions from Jonathan: pass an extra . to the helper macro so that something sensible happens when the input string doesn't contain one; use \@nil instead of \relax as the 'special token', now needing \makeatletter protection, as LaTeX itself uses \@nil for similar purpose and it is less likely to appear in the argument (and if it does, is more likely to generate a meaningful error).

  • +1, sorry I didn't notice this answer when I posted, I deleted mine (which was identical, more or less) – David Carlisle Sep 15 '13 at 11:41
  • you could make your \fooex safer by something like \newcommand{\foo}[1]{\getfirst#1..\@nil} \def\getfirst#1.#2.#3\@nil{#1}. This also works for cases like \foo{32}. – Jonathan Sep 15 '13 at 11:59
  • @Jonathan: thanks, I have updated my answer using something similar to your suggestion, but I am not sure why you suggest adding an extra dotted component? – cyberSingularity Sep 15 '13 at 12:33
  • @cyberSingularity you're right, of course. The extra dot is only needed if you also want to work with #2 which always contains a trailing dot in this case .... – Jonathan Sep 15 '13 at 12:44
  • you could replace \@nil by \fooex itself, thus avoiding the \makeatletter. –  Sep 15 '13 at 15:01
  • @jfbu: thanks, that would certainly work. However, I will not merge this into the answer as I feel that the current version is easier to read, in a sense. Please retain your comment here for the benefit of others though! – cyberSingularity Sep 15 '13 at 15:33
2

This is the stringstrings approach. Things to know about it:

[q] is quiet mode, [v] is verbose mode. The package stores results of string manipulations in the expanded result \thestring, and results of string "queries" in \theresult. So in the macro \test, you can do whatever you want with the expanded \thestring (in this case, I just print it).

\documentclass{book}
\usepackage{stringstrings}

\newcounter{tempdot}

\newcommand{\foo}[2][v]{%
  \whereischar[q]{#2}{.}%
  \setcounter{tempdot}{\theresult}%
  \addtocounter{tempdot}{-1}%
  \substring[#1]{#2}{1}{\thetempdot}%
}

\newcommand\test[1]{%
  \foo[q]{#1}%
  \thestring%
}

\begin{document}
\noindent
Result of foo\{3.2\}: \foo{3.2}\\
Result of test\{3.2\}: \test{3.2}

\end{document}
ShreevatsaR
  • 45,428
  • 10
  • 117
  • 149