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}
3
  • 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
    Commented Nov 4, 2013 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. Commented Nov 4, 2013 at 15:09
  • @percusse Is that better now? Commented Nov 5, 2013 at 2:16

2 Answers 2

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

2
  • 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? Commented Nov 4, 2013 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 Commented Nov 5, 2013 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
\[email protected]
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

7
  • While I've seen it before, I remain in awe of the roman-numeral trick. Commented Nov 4, 2013 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
    Commented Nov 4, 2013 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
    Commented Nov 4, 2013 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
    Commented Nov 4, 2013 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
    Commented Nov 4, 2013 at 14:59

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .