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}
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}
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. – user4686 Sep 15 '13 at 15:01
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}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.