预定义的 LaTeX 单位(例如 pt 或 em)使用方式如下:
\newlength\somelength
\setlength\somelength{3.5em}
也就是说,乘数直接位于单位前面,中间没有反斜杠。TeX 知道“em”是特定大小,具体取决于布局。
我可以做这个:
\newlength\bs % where \bs is not otherwise used
\setlength\bs{11.46pt}
\newlength\somelength
\setlength\somelength{3.5\bs}
但我想问的是,可以不用反斜杠吗?我这里指的不是“SIunits”。所需伪代码:
\newmeasurement\bs
\setmeasurement\bs{11.46pt}
\newlength\somelength
\setlength\somelength{3.5bs} % no backslash needed
有没有一种“简单”的方法可以做到这一点,并且具有普遍适用性?我正在使用 LuaLaTeX 和 TeXlive 2016,但希望在 TeX 核心深处有一些简单的方法可以做到这一点,但我还没有发现。早期的搜索找到了格式化单位的方法,而不是将它们定义为基本单位。
如果问题不切实际,我会接受。不能拥有一切。
编辑:显然这不容易做到。当我问这个问题时,我想也许有一个命令我不知道。所以它可以被关闭。
答案1
正如评论所述,TeX 已知的单位是在 Pascal 源代码中实现的。但正如 Joseph Wright 在其评论中指出的那样,您可以编写宏来执行您想要的操作。
两个假设:
- 对单元使用两个字符,就像 TeX 对所有其他单元所做的那样。(这避免了很多测试。)
- 始终使用新单位作为花括号中的宏参数。
\Setlength
我展示了两个宏和的一般方法\Hspace
,它们在您的问题和评论中提到过。请注意,我不会更改 LaTeX 宏。
我以纯 TeX 样式编写宏。宏不会检查单位是否是已知单位(如 pt)。因此它们只能与您自己的单位一起使用。此外,如果使用未知单位调用它们,它们不会给出有用的错误消息。正如我所写,我只给出了解决问题的一般方法。
\newdimen\ownunitdimen
\def\rev#1#2\rev{\ifx\rev#2\rev#1\else\rev#2\rev#1\fi}% a TeX pearl
\def\applyownunit#1#2#3\done{% needs \#2#1factor and \#2#1unit
\global\ownunitdimen=\rev #3\rev\csname #2#1unit\endcsname
\global\ownunitdimen=\csname #2#1factor\endcsname\ownunitdimen\ignorespaces}
\def\Setlength#1#2{\bgroup\edef\reverse{\rev #2\rev}%
\expandafter\applyownunit\reverse\done\egroup
\csname #1\endcsname=\ownunitdimen}
\def\Hspace#1{\bgroup\edef\reverse{\rev #1\rev}%
\expandafter\applyownunit\reverse\done\egroup
\hskip\ownunitdimen\relax}
% define new units; avoid dimen registers
\def\dmfactor{10}\def\dmunit{cm}% 1 dm = 10 cm
\def\pzfactor{2.2633484517438}\def\pzunit{mm} % 1 pz \approx 2.2633484517438 mm
% see page 26 of ``Selected Papers on Fun \& Games'' by Donald E. Knuth
% test
\newdimen\A \newdimen\B
\Setlength{A}{8.97dm}% use the new unit
\B=89.7cm % and compare it to this
A: \the\A \Hspace{5,2pz}B: \the\B\par % use the new unit in European style
A: \the\A \hskip11.76941194906776mm B: \the\B % and compare
% I think this is better
\newdimen\pz \pz=2.2633484517438mm
A: \the\A \hskip5.2\pz B: \the\B
\bye
答案2
一种可能的方法是逐个标记地迭代,提取一个双字母单位并查看它是否已被定义。为了允许宏隐藏在那里,我曾经\expanded
强制扩展:这可以避免。同样,我允许将新单位指定为(标准)e-TeX 维度表达式:我们也可以在那里允许新单位。
捡字母的诀窍相对其他一切都使用字符代码:这样,我们就可以进行一个非常简单的测试:
\protected\def\setlength#1#2{%
\expandafter\setlengthauxi\expandafter#1\expanded{#2}\relax{}%
}
\protected\def\setlengthauxi#1#2{%
\ifx#2\relax
\expandafter\setlengthnounit
\fi
\ifnum 0%
\ifnum`#2<`a 1\fi%
\ifnum`#2>`z 1\fi%
>0 %
\expandafter\setlengthstore
\else
\expandafter\setlengthletter
\fi
#1#2%
}
\protected\def\setlengthstore#1#2#3\relax#4{%
\setlengthauxi#1#3\relax{#4#2}%
}
\protected\def\setlengthletter#1#2#3{%
\ifx#3\relax
\expandafter\ERROR
\fi
\setlengthletterauxi#1{#2#3}%
}
\protected\def\setlengthletterauxi#1#2#3{%
\ifx#3\relax
\else
\expandafter\ERROR
\fi
\setlengthletterauxii#1{#2}%
}
\protected\def\setlengthletterauxii#1#2#3{%
\ifcsname unit@\expandafter\string\csname#2\endcsname\endcsname
#1 = #3\csname unit@\expandafter\string\csname#2\endcsname\endcsname\relax
\else
#1 = #3#2\relax
\fi
}
\protected\def\setlengthnounit#1\setlengthletter\fi#2#3#4{#2 = #4 }
\protected\def\newlength#1{\csname newskip\endcsname#1}
\protected\def\newmeasurement#1#2{%
\expandafter\newlength\csname unit@\string#1\endcsname
\csname unit@\string#1\endcsname = \dimexpr#2\relax\relax
}
\newmeasurement\bs{11.46pt}
\newlength\somelength
\setlength\somelength{3.5bs}
\showthe\somelength