7

For historical reasons, I've been using the units package in my thesis to typeset numbers with units or units with \usepackage[tight]{units}

For formatting numbers in table columns I'm already using the siunitx package and I'd also like to use it for the numbers with units and units. However in the large document (>300 pages) I can not replace all (>500) occurences of the \unit[]{}command by hand.

What is a good strategy for replacing the old commands with new ones?

I assume it is not sufficient to replace \unit[ by \SI[ or is the "syntax" of optional arguments and arguments "compatible" for both commands?

6

The units package is quite easy to emulate reasonably. I'd recommend using the LaTeX3 \DeclareDocumentCommand macro:

\documentclass{article}
%\usepackage{units}
\usepackage{siunitx}
\sisetup{detect-weight, per-mode = fraction}
\DeclareDocumentCommand\unit{om}{%
  \IfNoValueTF{#1}{\si{#2}}{\SI{#1}{#2}}%
}
\begin{document}
\unit{m}
\unit[10]{m}
\end{document}
  • Thanks Joseph! 2 questions: 1) Are you sure, that this will give comparable results like the original \unit command, if I just use their arguments with \si or ´\SI? Could there be any cases where it does not work? 2) I'm using "standard" LaTeX which is IMHO a version <3 (LaTeX2e <2009/09/24>`). Can I just use the LaTeX3-macro then? – MostlyHarmless Jul 31 '11 at 22:34
  • You can use LaTeX3 macros if you load suitable packages, in this case xparse, I guess; however, this is loaded by siunitx anyway, so you don't have to declare it (although doing so might be a good practice imho). See latex-project.org/latex3.html for more info on LaTeX3. – mbork Aug 1 '11 at 8:56
  • @Martin: This is the approach I took in v1 of \siunitx, where a lot of testing did look okay. Currently, 'LaTeX3' means the expl3 layer on top of LaTeX2e. siunitx loads the expl3 layer, so you should have no issues. – Joseph Wright Aug 1 '11 at 16:22
6

Since the syntax for units is \unit[<value>]{<unit>}, one has to use two different commands of siunitx:

\makeatletter
\let\unit\relax % to "undefine" it
\DeclareRobustCommand{\unit}{\@ifnextchar[\my@si\si}
\def\my@si[#1]#2{\SI{#1}{#2}}
\makeatother

Alternatively

\makeatletter
\let\unit\relax % to "undefine" it
\DeclareRobustCommand{\unit}[2][]{%
   \if\relax\detokenize{#1}\relax % check if optional argument is empty
     % no value
     \si{#2}%
   \else
     % value is given
     \SI{#1}{#2}
   \fi}
 \makeatother
5

I would definitely do it using regular expressions. You'd have it without macro trickery (which isn't always what one wants) and - as an additional bonus - you'd learn to use a powerful tool.

In Emacs (this is kind of important, since emacs', perl's etc. regexps are sometimes slightly different) I'd use the following transformations (using query-replace-regexp):

\\unit\[\(.+?\)\]{\(.+?\)}    ->    \\SI{\1}{\2}

and

\\unit{\(.+?\)}    ->    \\si{\1}

This assumes that you have no ]'s in the optional argument and no }'s in the mandatory one; if you have nested constructs etc., you'll have to either:

  • use egreg's approach;
  • concoct a more clever regexp to do it automatically;
  • (my favourite) first create a regexp to find such cases automatically and correct them manually (assuming that such cases are rather rare, of course).

Notice that in the very first regexp, instead of .+?, you could use something more specific, like [0-9.]+ (assuming you have only raw numbers, which is probably the case); then you wouldn't need the question mark, which denotes a so-called non-greedy operator (consume as few characters as possible instead of as many).

A concluding remark is that while regexps seem terrifying at first sight, believe me that once you get hang of them, your life will be easier.

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.