Stripping the pt from a dimension
On the 'PT' question, what is needed is the lower case tokens p
and t
with category code 12. As you say, \the<dimen>
returns the value of the followed by pt
, but these are 'other' tokens and not 'letters'. So something like
\def\rem@pt#1.#2pt{...
will not work, even with \lowercase
(which changes character codes but not category codes): TeX would keep looking for the characters 'pt' with category code 'other', would probably not find them and would raise an error.
On the second question, \x\endgroup
will only define \rem@pt
inside the group you then close. You could use \gdef
to get round this, but the \expandafter
route also works as the content of \x
is expanded outside of the group. Your example still compiles as the kernel has already globally defined \rem@pt
. Try giving it a different name in your example and observe the 'Undefined control sequence error' that occurs when you expand \x
before closing the group.
An alternative way to create the same macro but without using \lowercase
is
\edef\rem@pt{%
\def\noexpand\rem@pt##1.##2\string p\string t{%
##1\noexpand\ifnum##2>\noexpand\z@.##2\noexpand\fi
}
}
\rem@pt
This works by creating the 'string' pt
using the \string
primitive (with e-TeX, you could also use \detokenize
). The first definition for \rem@pt
sets up for the second definition, which is then ultimately the same as the LaTeX kernel method.
A LaTeX3 implementation was requested in comments. At present, we have an internal function \__dim_strip_pt:n
to do the job: this is very much in the same vein as the LaTeX2e code, but with dimension expression evaluation. The set up currently reads
\cs_new:Npn \__dim_strip_pt:n #1
{
\exp_after:wN
\__dim_strip_pt:w \dim_use:N \__dim_eval:w #1 \__dim_eval_end: \q_stop
}
\use:x
{
\cs_new:Npn \exp_not:N \__dim_strip_pt:w
##1 . ##2 \tl_to_str:n { pt } ##3 \exp_not:N \q_stop
{
##1
\exp_not:N \int_compare:nNnT {##2} > \c_zero
{ . ##2 }
}
}
where \dim_use:N \__dim_eval:w #1 \__dim_eval_end:
is the same as \dim_eval:n
but avoids needing to force expansion twice, which would be done using
\cs_new:Npn \__dim_strip_pt:n #1
{
\exp_after:wN \exp_after:wN \exp_after:wN
\__dim_strip_pt:w \dim_eval:n {#1} \q_stop
}
If there is a broader need for this 'strip the pt
function then it can be moved from internal to general use. (It's intended to support driver-level code, which is written by the team and is therefore internal.)
An alternative definition is used in ConTeXt which does not use that \lowercase
trick. The following code is taken from syst-aux.mkiv
.
%D \macros
%D {withoutpt,PtToCm,
%D numberofpoints,dimensiontocount}
%D
%D We can convert point into centimeters with:
%D
%D \starttyping
%D \PtToCm{dimension}
%D \stoptyping
{\catcode`\.=\othercatcode
\catcode`\p=\othercatcode
\catcode`\t=\othercatcode
\gdef\WITHOUTPT#1pt{#1}}
\def\withoutpt#1%
{\expandafter\WITHOUTPT#1}
%D The capitals are needed because \type{p} and \type{t} have
%D \CATCODE~12, while macronames only permit tokens with the
%D \CATCODE~11. As a result we cannot use the \type{.group}
%D primitives. Those who want to know more about this kind of
%D manipulations, we advice to study the \TEX book in detail.
%D Because this macro does not do any assignment, we can use it
%D in the following way too.
\def\PtToCm#1%
{\withoutpt\the\dimexpr0.0351459804\dimexpr#1\relax\relax cm}
Unlike the LaTeX macro, this macro is not trying to truncate the digits after the decimal point and leaves it upto the user to add \the
when needed.