具有任意数量参数的控制序列

具有任意数量参数的控制序列

我想要一个可以生成由多个基本单位组成的单位的宏。让宏为\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}

在此处输入图片描述

相关内容