9

Firstly, my apologies for any previous confusion, I've separated out various questions onto distinct pages.

This problem came up in the context of trying to split a decimal number. Good solutions to both my questions with pgf and package independent have been provided or will be soon on those pages.

The main intent of this question is that I'm trying to better understand how things are expanded in LaTeX. There is good information in the answers below about just this aspect. Perhaps if those people wouldn't mind moving sidetrack stuff to either of the two questions linked above to help me simplify the situation. I realise this is a bit tricky as the expansion idea was being discussed in the context of splitting a length. Thanks in advance.

The MWE is just a whole bunch of ideas I was experimenting with, trying to expand values to get at what I wanted and failing because I don't yet fully understand how LaTeX, or TeX, expands various types of value.

MWE Output

MWE Output

MWE Code

\documentclass[12pt]{article}
\usepackage[a5paper,margin=14mm]{geometry}

\makeatletter
\def\printplainbefore#1{\expandafter\@printplainbefore#1..\@nil}
\def\@printplainbefore#1.#2.#3\@nil{#1}
\def\printplainafter#1{\expandafter\@printplainafter#1..\@nil}
\def\@printplainafter#1.#2.#3\@nil{#2}

\newcommand*{\getlength}[1]{\strip@pt#1}

\makeatother

\def\mythe#1{\expandafter\getlength{#1}}

\newcommand{\savenum}[2]{\expandafter\xdef\csname num#1\endcsname{#2}}
\newcommand{\getnum}[1]{\csname num#1\endcsname}

\newlength{\thislength}
\setlength{\thislength}{123.456pt}
\tracingmacros=1

\begin{document}
\par The: \the\thislength
    \quad Split: \printplainbefore{\the\thislength} -- \printplainafter{\the\thislength}
\par Getlength: \getlength{\thislength}
    \quad Split: \printplainbefore{\getlength{\thislength}} -- \printplainafter{\getlength{\thislength}}
\par MyThe: \mythe\thislength
    \quad Split: \printplainbefore{\mythe\thislength} -- \printplainafter{\mythe\thislength}
\par Getlength variable first: \getlength{\thislength}
    \quad Split: \xdef\test{\getlength{\thislength}} \printplainbefore{\test} -- \printplainafter{\test}
\par Getlength save: \getlength{\thislength}
    \quad Split: \savenum{thislength}{\getlength{\thislength}} \printplainbefore{\getnum{thislength}} -- \printplainafter{\getnum{thislength}}
\end{document}
  • 1
    I think you need to distill the questions a little further, if I may comment on the style. It's a lot of code to get to the bottom of your problem. – percusse Nov 4 '13 at 15:05
  • @percusse It's not one solution, I was just showing all the different ways I had experimented with trying to solve it. Anyway, A.Ellet's answer has helped me no end. – Geoff Pointer Nov 4 '13 at 15:09
  • @percusse Is that better now? – Geoff Pointer Nov 5 '13 at 2:16
8

I'm a bit confused by your code. But there are a couple of things I see that might help you.

Writing

\expandfater\getlength{#1}

is effectively the same as writing

\getlength{#1}

without any expansion.

If it's #1 that you want expanded first, that's not going to happen as you wrote it. Instead, it's the { TeX is going to try to expand. To reach #1 you need to write something like

\expandafter\getlength\expandafter{#1}

But this most likely won't do what you want either. If #1 is a string of tokens, for example if you try

\def\a{ABC}
\def\b{\c}
\def\c{XYZ}
\def\mythe#1{\expandafter\getlength\expandafter{#1}}

Then

\mythe{\a\b\c}

expands to

\expandafter\getlength\expandafter{\a\b\c}

which then expands to

\getlength{ABC\b\c}

The \b\c of #1 is not accessible through the use of \expandafter as you've written it. Now, if you know that #1 should only be one token, that all is OK at this point.

If you want to get the integer and fractional parts of a dimension, then the following will accomplish that without calling any special packages.

\documentclass{article}
\makeatletter

\def\getparts#1{%%
  \edef\my@stripped@length{\strip@pt#1}%%
  \expandafter\ae@int@frac\my@stripped@length..\@nil
}

\def\ae@int@frac#1.#2.#3\@nil{%%
  \def\aeinteger{#1}%%
  \def\aefraction{#2}%%
}

\newlength{\aetemp}
\setlength{\aetemp}{1.234cm}

\def\showparts{%%
  \begin{tabular}{ll}\hline
  Length   & \the\aetemp\\
  Integer  & \aeinteger \\
  Fraction & \aefraction\\\hline
  \end{tabular}}


\makeatother
\pagestyle{empty}
\begin{document}

\setlength{\aetemp}{1cm}
\getparts{\aetemp}
\showparts

\setlength{\aetemp}{215pt}
\getparts{\aetemp}
\showparts

\end{document}

enter image description here

  • I said in my question, I'm basically trying to get the result of the \getlength function to expand inline, so my printplain functions can read it. My code is probably confusing because it includes a variety of pathetic attempts to do so. But what you've done, is what I was trying to do. What I still don't get is, if \getlength has removed the `pt, why can't my functions just read what's left? – Geoff Pointer Nov 4 '13 at 8:29
  • I've clarified the question, I hope you don't mind helping me do what I suggest. You could always move part of what you have here to an answer here. Then we could try and separate discussion of expanding expressions from the particular problem of splitting a decimal. Cheers – Geoff Pointer Nov 5 '13 at 2:19
6

The problem is that \getlength requires several expansion steps to end its job delivering a sequence of digits (with a decimal dot in the middle). I'll show them in successive lines

\getlength{\thislength}
\strip@pt\thislength
\expandafter\rem@pt\the\thislength
\rem@pt123.456pt
123\ifnum 456>\z@ .456\fi
123.456

A total of five expansion steps that require 31 \expandafter tokens to be performed if you want that \@printplainbefore to see what it expects, not just one. But the presence of \ifnum makes the macro unusable in practice.

Since you don't want to remove a zero fractional part, you can use a \romannumeral trick:

\documentclass{article}

\makeatletter
\def\printplainbefore#1{\expandafter\@printplainbefore\romannumeral-`Q#1..\@nil}
\def\@printplainbefore#1.#2.#3\@nil{#1}
\def\printplainafter#1{\expandafter\@printplainafter\romannumeral-`Q#1..\@nil}
\def\@printplainafter#1.#2.#3\@nil{#2}

\begingroup\catcode`P=12 \catcode`T=12
\lowercase{\endgroup\def\simplerem@pt#1PT{#1}}
\def\simplestrip@pt{\expandafter\simplerem@pt\the}
\newcommand*{\getlength}[1]{\simplestrip@pt#1}

\makeatother

\newlength{\thislength}
\setlength{\thislength}{123.456pt}

\begin{document}
Number: 123.456
    \quad Split: \printplainbefore{123.456} -- \printplainafter{123.456}

\def\temp{123.456}
Macro: \texttt{\meaning\temp}
    \quad Split: \printplainbefore{\temp} -- \printplainafter{\temp}

The: \the\thislength
    \quad Split: \printplainbefore{\the\thislength} -- \printplainafter{\the\thislength}

Getlength: \getlength{\thislength}
    \quad Split: \printplainbefore{\getlength{\thislength}} -- \printplainafter{\getlength{\thislength}}

\end{document}

enter image description here

  • While I've seen it before, I remain in awe of the roman-numeral trick. – Steven B. Segletes Nov 4 '13 at 11:50
  • @StevenB.Segletes The secret is that after each expansion stage a macro is found at the start of the resulting token list, except for the last step where the result is obtained. – egreg Nov 4 '13 at 12:45
  • Question 1: I'm really confused by the \romannumeral trick. I've seen a partial explanation which still leaves me in a bit of a fog. But your code above uses <open quote>Q. I thought \romannumeral stops at the first unexpandable token. Wouldn't that be the opening quote mark? – A.Ellett Nov 4 '13 at 14:07
  • Question 2: The other trick you use is something else I don't fully understand. It's \begingroup...\lowercase{\endgroup I don't understand how the \catcode changes are preserved in \def\simplerem@pt#1PT{#1}. Has there already an answer posted somewhere on this site? Or should I post this as a question to the larger community? – A.Ellett Nov 4 '13 at 14:10
  • @A.Ellett I believe there's already something on the subject. The trick is that \lowercase does nothing else on its argument than lowercasing character tokens (using the \lccode array): no expansion or execution of commands is performed and category codes are preserved (only the character codes are changed). So when the \endgroup is executed, P and T have already been changed to their lowercase version (with category code 12). – egreg Nov 4 '13 at 14:59

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.