我想修改\int
命令,使其添加自动负空格,例如\!
在积分符号后。我更希望能够不编辑任何代码,因此巧妙地重新定义\int
似乎是我最好的选择。不幸的是,简单的实现会弄错限制:
\documentclass{article}
\usepackage[intlimits]{amsmath}
\usepackage{ifthen}
\newcommand{\diff}[2][]{
\ifthenelse { \equal {#1} {} }
{\ensuremath{\mathop{\mathrm{d} #2}}}
{\ensuremath{\mathop{\mathrm{d}^#1 #2}}}
}
\begin{document}
This is what I would want:
\begin{equation}
\int_0^\infty \mspace{-4mu}\diff[3]{\boldsymbol r} f(\boldsymbol r),
\end{equation}
but with this ``user code", containing no negative spacing explicitly:
\begin{verbatim}
\int_0^\infty \diff[3]{\boldsymbol r} f(\boldsymbol r),
\end{verbatim}
which for comparison with the above gives:
\begin{equation}
\int_0^\infty \diff[3]{\boldsymbol r} f(\boldsymbol r),
\end{equation}
mostly because this gives me the option to remove it or change the spacing when I see fit.
\end{document}
其结果是:
答案1
使用此代码
\usepackage{etoolbox}
\newcommand*\diff[2][]{\mathop{\mathrm{d}\ifblank{#1}{}{^{#1}}{#2}}}
\let\originalint\int
\def\int_#1^#2{\originalint_{#1}^{#2}\mathopen{}}
删除后面的空格,\int
但代码必须始终使用\int_{..}^{..}
限制并按照特定顺序编写。您可以编写一些技巧,以便如果限制为空,则不会将其添加到代码中。或者您可以使用一些技巧,\@ifnextchar
以便以任何顺序检查两个限制,结果更干净。如果需要,我可以添加。这是代码(感谢@kyle_the_hacker):
\usepackage{etoolbox}
\makeatletter
\newcommand*\diff[2][]{\mathop{\mathrm{d}\ifblank{#1}{}{^{#1}}{#2}}}
\let\int@original\int
\def\int{\int@checkfirstsb}
\def\int@checkfirstsb{\@ifnextchar_{\int@checksecondsp}{\int@checkfirstsp}}
\def\int@checkfirstsp{\@ifnextchar^{\int@checksecondsb}{\int@{}{}}}
\def\int@checksecondsp_#1{\@ifnextchar^{\int@grabsp{#1}}{\int@{#1}{}}}
\def\int@checksecondsb^#1{\@ifnextchar_{\int@grabsb{#1}}{\int@{}{#1}}}
\def\int@grabsb#1_#2{\int@{#2}{#1}}
\def\int@grabsp#1^#2{\int@{#1}{#2}}
\def\int@#1#2{\int@original\ifblank{#1}{}{_{#1}}\ifblank{#2}{}{^{#2}}\mathopen{}}
\makeatother
无论如何,这是一个机会来添加我前段时间写的一些代码向 xparser 添加新类型的参数。
\documentclass{scrartcl}
\usepackage[intlimits]{amsmath}
\usepackage{etoolbox,xparse}
\ExplSyntaxOn
\cs_new_protected:Npn \__xparse_count_type_k:w #1
{
\__xparse_single_token_check:n { #1 }
\quark_if_recursion_tail_stop_do:Nn #1 { \__xparse_bad_arg_spec:wn }
\__xparse_count_mandatory:N
}
\cs_new_protected:Npn \__xparse_count_type_K:w #1 #2
{
\__xparse_single_token_check:n { #1 }
\quark_if_recursion_tail_stop_do:nn { #2 } { \__xparse_bad_arg_spec:wn }
\__xparse_count_mandatory:N
}
\cs_new_protected:Npn \__xparse_add_type_k:w #1
{ \exp_args:NNo \__xparse_add_type_K:w #1 { \c__xparse_no_value_tl } }
\cs_new_protected:Npn \__xparse_add_type_K:w #1 #2
{
\__xparse_flush_m_args:
\__xparse_add_grabber_optional:N K
\tl_put_right:Nn \l__xparse_signature_tl { #1 { #2 } }
\__xparse_prepare_signature:N
}
\cs_new_protected:Npn \__xparse_add_expandable_type_k:w #1
{
\exp_args:NNo \__xparse_add_expandable_type_K:w #1 { \c__xparse_no_value_tl }
}
\cs_new_protected_nopar:Npn \__xparse_add_expandable_type_K:w #1 #2
{
\__msg_kernel_error:nnx { xparse } { invalid-expandable-argument-type } { K }
\__xparse_add_expandable_type_m:w % May be create this?
}
\cs_new_protected:Npn \__xparse_grab_K:w #1 #2 #3 \l__xparse_args_tl
{
\__xparse_grab_K_aux:NnnNn #1 { #2 } { #3 } \cs_set_protected_nopar:Npn
{ _ignore_spaces }
}
\cs_new_protected:Npn \__xparse_grab_K_long:w #1 #2 #3 \l__xparse_args_tl
{
\__xparse_grab_K_aux:NnnNn #1 { #2 } { #3 } \cs_set_protected:Npn
{ _ignore_spaces }
}
\cs_new_protected:Npn \__xparse_grab_K_trailing:w #1 #2 #3 \l__xparse_args_tl
{
\__xparse_grab_K_aux:NnnNn #1 { #2 } { #3 } \cs_set_protected_nopar:Npn
{ _ignore_spaces }
}
\cs_new_protected:Npn \__xparse_grab_K_long_trailing:w #1 #2 #3 \l__xparse_args_tl
{
\__xparse_grab_K_aux:NnnNn #1 { #2 } { #3 } \cs_set_protected:Npn
{ _ignore_spaces }
}
\cs_new_protected:Npn \__xparse_grab_K_aux:NnnNn #1 #2 #3 #4 #5
{
\exp_after:wN #4 \l__xparse_fn_tl ##1
{
\__xparse_add_arg:n { ##1 }
#3 \l__xparse_args_tl
}
\use:c { peek_meaning_remove #5 :NTF } #1
{ \l__xparse_fn_tl }
{
\__xparse_add_arg:n { #2 }
#3 \l__xparse_args_tl
}
}
\prop_put:Nnn \c__xparse_shorthands_prop { a } { k \sb }
\prop_put:Nnn \c__xparse_shorthands_prop { b } { k \sp }
\prop_put:Nnn \c__xparse_shorthands_prop { A } { K \sb }
\prop_put:Nnn \c__xparse_shorthands_prop { B } { K \sp }
\NewDocumentCommand \diff { o m }
{\mathop{\mathrm{d}\IfValueT{#1}{^{#1}}{#2}}}
\ExplSyntaxOff
\let\originalint\int
\RenewDocumentCommand \int { a b }
{\originalint\IfValueT{#1}{_{#1}}\IfValueT{#2}{^{#2}}\mathopen{}}
\begin{document}
\begin{equation}
\int_0^\infty \diff[3]{\boldsymbol r} f(\boldsymbol r)
\end{equation}
\end{document}
甚至可能更好地检查是否\diff
遵循,如果它不只是具有原始行为,只需将定义更改为此(遗憾的是没有跳过空格,所以我们需要明确检查空格,然后检查之后的\diff
)
\makeatletter
\RenewDocumentCommand \int { a b t\@sptoken t\diff }
{\originalint\IfValueT{#1}{_{#1}}\IfValueT{#2}{^{#2}}%
\IfBooleanT{#4}{\mathopen{}\diff}}
\makeatother
经过一番思考
完成重新思考代码,我将使用它来实现完全的灵活性。这将为\int
加上自然的差分输入\dd x
, \dd{\bm x}
, \dd^2 x
, \dd^{a_1}{x_1}
。
\usepackage{mathtools,bm}
\usepackage{etoolbox}
\makeatletter
\def\dd{\@ifnextchar^{\dd@grabsp}{\dd@{}}}
\def\dd@grabsp^#1#2{\dd@{#1}{#2}}
\def\dd@#1#2{\mathop{d\ifblank{#1}{}{^{#1}}{#2}}}
\let\int@original\int
\def\int{\int@checkfirstsb}
\def\int@checkfirstsb{\@ifnextchar_{\int@checksecondsp}{\int@checkfirstsp}}
\def\int@checkfirstsp{\@ifnextchar^{\int@checksecondsb}{\int@{}{}}}
\def\int@checksecondsp_#1{\@ifnextchar^{\int@grabsp{#1}}{\int@{#1}{}}}
\def\int@checksecondsb^#1{\@ifnextchar_{\int@grabsb{#1}}{\int@{}{#1}}}
\def\int@grabsb#1_#2{\int@{#2}{#1}}
\def\int@grabsp#1^#2{\int@{#1}{#2}}
\def\int@#1#2{\int@original\ifblank{#1}{}{_{#1}}\ifblank{#2}{}{^{#2}}\mathopen{}}
\makeatother
使用xparse
之前的代码
\NewDocumentCommand\dd{bm}{\mathop{d\IfValueT{#1}{^{#1}}{#2}}}
\let\originalint\int
\RenewDocumentCommand\int{ab}{\originalint\IfValueT{#1}{_{#1}}\IfValueT{#2}{^{#2}}\mathopen{}}
答案2
随着最新版本的发布,这变得非常容易xparse
:
\documentclass{article}
\usepackage[intlimits]{amsmath}
\usepackage{bm}
\usepackage{xparse}
\let\oldint\int % for the comparison
\RenewDocumentCommand{\int}{e{_^}}{%
\DOTSI
\intop_{\IfValueT{#1}{#1}}^{\IfValueT{#2}{#2}}%
\mspace{-4mu}%
}
\NewDocumentCommand{\diff}{om}{% equivalent, but easier with xparse
\mathop{\mathrm{d}\IfValueT{#1}{^{#1}}#2}
}
\begin{document}
This is the normal typesetting
\begin{equation}
\oldint_0^\infty \diff[3]{\bm{r}} f(\bm{r}),
\end{equation}
This is what I would want:
\begin{equation}
\oldint_0^\infty \mspace{-4mu}\diff[3]{\bm{r}} f(\bm{r}),
\end{equation}
and this is what we get
\begin{equation}
\int_0^\infty \diff[3]{\bm{r}} f(\bm{r}),
\end{equation}
\end{document}
然而,这是一个假问题,主要是由于 的错误定义插入了虚假空间\diff
。
确实,与
\documentclass{article}
\usepackage[intlimits]{amsmath}
\usepackage{bm}
\usepackage{xparse}
\NewDocumentCommand{\diff}{om}{% note \!
\mathop{\!\mathrm{d}\IfValueT{#1}{^{#1}}#2}
}
\begin{document}
This is the normal typesetting
\begin{equation}
\int_0^\infty \diff[3]{\bm{r}} f(\bm{r}),
\end{equation}
\end{document}
答案3
之前发布的答案是巨大的并且具有复杂的依赖关系,我尝试提出一个更紧凑的解决方案,并得出以下结论:
代码
将其拖放到文档中的任意位置,在第一次使用之前\int
。
\makeatletter
\let\MyIntOrig\int
\def\MyIntSpace{\hspace{-.5em}} %% Configure as needed.
\def\int{\MyInt}
\def\MyInt{\MyIntOrig\MyIntSkipMaybe}
\def\MyIntSkipMaybe{
\@ifnextchar_{\MyIntSkipScript}{%
\@ifnextchar^{\MyIntSkipScript}{%
\@ifnextchar\limits{\MyIntSkipTok}{%
\@ifnextchar\nolimits{\MyIntSkipTok}{%
%% Add more cases here as needed. Keep in mind to close the braces.
\MyIntSpace}}}}%
}
\def\MyIntSkipScript#1#2{#1{#2}\MyIntSkipMaybe}
\def\MyIntSkipTok#1{#1\MyIntSkipMaybe}
\makeatother
最小工作文档
\documentclass[12pt]{article}
\usepackage{amsmath}
\begin{document}
\makeatletter
\let\MyIntOrig\int
\def\MyIntSpace{\hspace{-.5em}} %% Configure as needed.
\def\int{\MyInt}
\def\MyInt{\MyIntOrig\MyIntSkipMaybe}
\def\MyIntSkipMaybe{
\@ifnextchar_{\MyIntSkipScript}{%
\@ifnextchar^{\MyIntSkipScript}{%
\@ifnextchar\limits{\MyIntSkipTok}{%
\@ifnextchar\nolimits{\MyIntSkipTok}{%
%% Add more cases here as needed. Keep in mind to close the braces.
\MyIntSpace}}}}%
}
\def\MyIntSkipScript#1#2{#1{#2}\MyIntSkipMaybe}
\def\MyIntSkipTok#1{#1\MyIntSkipMaybe}
\makeatother
\def\MyTry#1{%
& {\let\int\MyIntOrig #1} &
& #1 &
& \text{\ttfamily\detokenize{#1}}&
}
\begin{align*}
& \text{Original} && \text{Redefined} && \text{Source} &\\
\MyTry{\int }\\
\MyTry{\int \int }\\
\MyTry{\int a\,dx}\\
\MyTry{\int _b a\,dx}\\
\MyTry{\int ^c a\,dx}\\
\MyTry{\int _b^c a\,dx}\\
\MyTry{\int _{from}^{to} a\,dx}\\
\MyTry{\int \limits_{from}^{to} a\,dx}\\
\MyTry{\int \nolimits_{from}^{to} a\,dx}\\
\MyTry{\int a_b x}
\end{align*}
\end{document}