我想要一个可以生成由多个基本单位组成的单位的宏。让宏为\unit
。例如,我想要\unit{kg}
表示\mathrm{kg}
和\unit{kg}{m}{s^{-2}}
表示\mathrm{kg \cdot m \cdot s^{-2}}
等。(尽管如何表示指数尚未决定)。
首先,我尝试了以下代码,但没有成功。错误日志显示Runway Argument? ! File ended while scanning use of \@unit. <inserted text> \par
。
\documentclass[uplatex]{jsarticle}
\makeatletter
\def\unit#1{\@unit#1}
\def\@unit#1{%
\ifx\bgroup#1
\mathrm{#1 \cdot}%
\else
\relax
\expandafter\@unit\fi}
\makeatother
%
\begin{document}
\unit{{kg}{m}}
\end{document}
我该如何定义期望\unit
?
答案1
假设你想要输入语法
\unit{kg}{m}
你需要做的是使用 TeX 原语\futurelet
来搜索即将到来的{
。如果有,我们可以抓取(带括号的)参数,在数学模式下排版,然后循环。请注意,这种方法需要每个参数都用括号括起来。
\documentclass{article}
\makeatletter
\def\unit{%
$%
\futurelet\@let@token\@unit
}
\def\@unit{%
\ifx\@let@token\bgroup
\expandafter\@@unit
\else
\expandafter$%
\fi
}
\def\@@unit#1{%
\mathrm{#1}%
\futurelet\@let@token\@@@unit
}
\def\@@@unit{%
\ifx\@let@token\bgroup
\cdot
\expandafter\@@unit
\else
\expandafter$%
\fi
}
\makeatother
\begin{document}
\unit{kg}{m}
\end{document}
为了允许插入,\cdot
我使用了两个辅助程序:一个仅用于第一个单元(省略)\cdot
,第二个插入所需的\cdot
。
答案2
这样做时的问题\def\@unit#1
在于,参数永远不会是括号,而是从左括号到匹配的闭括号的所有内容,因此测试永远不会成功。
您可以使用 来实现\futurelet
,但您将被束缚在一个非常不灵活的输入系统中。这是一个 expl3 实现,可能比 更清晰\futurelet
。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\unit}{}
{
% if we're not in math mode open it and remember to close it
\mode_if_math:F { $ \bool_set_true:N \l_merzong_close_bool }
% clear the container for the units
\seq_clear:N \merzong_units_seq
% start looking forward for an open brace
\merzong_scan_arg:
}
\cs_new_protected:Npn \merzong_scan_arg:
{
\peek_catcode:NTF \c_group_begin_token
{% the next token is an open brace, absorb the argument
\merzong_add_unit:n
}
{% the next token is not an open brace, deliver the units
% absorbed so far, with \unitmulti between them
\seq_use:Nn \merzong_units_seq { \unitmulti }
% close math mode if we started it
\bool_if:NT \l_merzong_close_bool { $ }
}
}
\cs_new_protected:Npn \merzong_add_unit:n #1
{
% absorb the argument and add it to the sequence
\seq_put_right:Nn \merzong_units_seq { \mathrm{#1} }
% restart the recursion
\merzong_scan_arg:
}
\seq_new:N \merzong_units_seq
\ExplSyntaxOff
\newcommand\useunitmultidot{\let\unitmulti=\cdot}
\newcommand\useunitmultispace{\let\unitmulti=\,}
\useunitmultidot % initialize
\begin{document}
\section{Centered dot}
\unit{kg}{m^2}{s^{-2}}
\section{Space}
\useunitmultispace
\unit{kg}{m^2}{s^{-2}}
\end{document}
您要做的事情已经由 完成siunitx
。使用它可确保您使用单位时的高度一致性。
\documentclass{article}
\usepackage{siunitx}
\begin{document}
\section{Centered dot}
\sisetup{inter-unit-product=\ensuremath{{}\cdot{}}}
\SI{3}{\kilo\gram\meter\squared\per\second\squared} or \SI{3}{kg.m^2.s^{-2}}
\section{Thin space}
\sisetup{inter-unit-product=\,}
\SI{3}{\kilo\gram\meter\squared\per\second\squared} or \SI{3}{kg.m^2.s^{-2}}
\section{Fraction for negative exponent}
\sisetup{per-mode=symbol}
\SI{3}{\kilo\gram\meter\squared\per\second\squared}
\end{document}