Simple implementation of the abs function by getting rid of or by consuming the "-"?
You could use xfp (the package is very short, it contains only two definitions to create wrappers around \fp_eval:n
and \int_eval:n
):
\documentclass{article}
\usepackage{xfp}
\begin{document}
\fpeval{abs(-12.3)}
\end{document}
It is expandable, that means you can fed it to \num
for formatting. Here I change the period to a command:
\documentclass{article}
\usepackage{xfp,siunitx}
\sisetup{locale=DE}
\begin{document}
\num{\fpeval{abs(-12.3)}}
\end{document}
You can define \gobbleminus
by this way:
\def\gobbleminus#1{\ifx-#1\else#1\fi}
%test:
\gobbleminus -12
\gobbleminus 1234
\gobbleminus .24
I'm sure you get a LaTeX3 solution by one of the experts in no time and I really don't think that a string-based solution is the best you can do here, but while you wait here is a simple, argument-based solution.
The solution is not expandable, which might be a bit of deal-breaker depending on what you want to do (but: see below).
The main idea is to use delimited arguments (How does TeX look for delimited arguments?) to strip characters from a string. In order not to run into trouble here, we first check whether the characters are actually present.
\ifstrstartswith
works by defining a helper macro \fstr@ifstrstartswith@i
that grabs arguments as follows
#1<characters to find>#2&
if we now pass a string to \fstr@ifstrstartswith@i
that starts with <characters to find>
, TeX's argument parse rules make #1
come up empty. In order to avoid errors, we always call \fstr@ifstrstartswith@i
with \fstr@ifstrstartswith@i <string><characters to find>&
. This means that even if <string>
does not contain <characters to find>
at all, we still have called the macro with the right argument signature.
The characters stripping now works similarly. We check that <string>
actually starts with <characters to remove>
and then apply a helper macro \fstr@stripfromstart@i
with signature
<characters to remove>#1&
which then strips off the <characters to remove>
from the beginning of <string>
when called as \fstr@stripfromstart@i <string>&
.
\documentclass[british]{article}
\usepackage[T1]{fontenc}
\usepackage{babel}
\usepackage{etoolbox}
\makeatletter
% {<characters to find>}{<string>}
\newrobustcmd*{\ifstrstartswith}[2]{%
\def\fstr@ifstrstartswith@i##1#1##2&{%
\ifblank{##1}}%
\fstr@ifstrstartswith@i#2#1&}
% {<characters to remove>}{<string>}
\newrobustcmd*{\stripfromstart}[2]{%
\def\fstr@stripfromstart@i#1##1&{##1}%
\ifstrstartswith{#1}{#2}
{\fstr@stripfromstart@i#2&}
{#2}}
\makeatother
\newcommand*{\mysimpleabs}{\stripfromstart{-}}
\begin{document}
\mysimpleabs{4.5}
\mysimpleabs{-4.5}
\end{document}
Of course you don't want to try \mysimpleabs{-4.5-5}
or \mysimpleabs{-4.5+5}
.
edit Come to think of it, we can make this expandable if we hard-code the -
. Still, string manipulation does not strike me as the best way to deal with this.
\documentclass[british]{article}
\usepackage[T1]{fontenc}
\usepackage{babel}
\usepackage{etoolbox}
\makeatletter
\newcommand*{\fstr@ifstrstartswithminus@i}{} % just to reserve the name
\def\fstr@ifstrstartswithminus@i#1-#2&{\ifblank{#1}}
\newcommand*{\ifstrstartswithminus}[1]{%
\fstr@ifstrstartswithminus@i#1-&}
\newcommand*{\fstr@stripminusfromstart@i}{} % just to reserve the name
\def\fstr@stripminusfromstart@i-#1&{#1}
\newcommand*{\stripminusfromstart}[1]{%
\ifstrstartswithminus{#1}
{\fstr@stripminusfromstart@i#1&}
{#1}}
\makeatother
\newcommand*{\mysimpleabs}{\stripminusfromstart}
\begin{document}
\mysimpleabs{4.5}
\mysimpleabs{-4.5}
\edef\foo{\mysimpleabs{12.3}}
\meaning\foo
\edef\foo{\mysimpleabs{-12.3}}
\meaning\foo
\end{document}