是否可以定义新单位,与 pt 或 em 相当?

是否可以定义新单位,与 pt 或 em 相当?

预定义的 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 在其评论中指出的那样,您可以编写宏来执行您想要的操作。

两个假设:

  1. 对单元使用两个字符,就像 TeX 对所有其他单元所做的那样。(这避免了很多测试。)
  2. 始终使用新单位作为花括号中的宏参数。

\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

相关内容