经过一番思考

经过一番思考

我想修改\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}

相关内容