7

For a while now I have tried to come up with a macro, that can properly format inegrals (the way I like). Aswell as giving it a few options that can be chosen e.g. \int and \oint. So far there is a little problem arising in the code. It occurs when you choose the \oint by adding a * to the argument. It does come with rigth integral, but the limits are a little wrong, since it contain too the * in the limits.

My Integral macro and an example is shown below

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}
\usepackage{xstring}

\NewDocumentCommand{\Int}{ >{\SplitList{;}}o}{%
    \IfValueT{#1}{\ProcessList{#1}{\IntLimitONE}}\,%
}
\NewDocumentCommand{\IntLimitONE}{m}{%
    \IfSubStr{#1}{*}{\oint\IntSplitLimits{#1}\!}{\int\IntSplitLimits{#1}\!}
}
\NewDocumentCommand{\IntSplitLimits}{ >{\SplitArgument{1}{,}}m}{%
    \IfValueT{#1}{\IntLimits#1}%
}
\NewDocumentCommand{\IntLimits}{mm}{%
    _{#1}^{\IfNoValueTF{#2}{}{#2\!\!}}%
}

\begin{document}
  \begin{equation}
     \Int[a,b;*c,d;e,f] f(x,y,z) dxdydz \quad , \quad \Int[*a,b] f(x) dx
  \end{equation}
\end{document}

enter image description here

I have tried a few ways to counter this, none satisfy completely my needs. One I tried was using the \xstring command \StrSubstitute

\NewDocumentCommand{\IntLimitONE}{m}{%
    \StrSubstitute{#1}{*}{}[\temp]%
    \IfSubStr{#1}{*}{\oint\IntSplitLimits{\temp}}{\int\IntSplitLimits{#1}}
}

It does indeed remove * from the limit, but the upper limit have been moved to the lower.

enter image description here

I cannot seem to understand what goes wrong here? Any help is appreciated :)

  • 2
    Does "fx." mean "for example"? The usual abbreviation in English is "e.g." – TRiG May 29 '17 at 23:16
  • 1
    @TRiG yes it does. I thougt the abbreviation was fx :) – Simon May 30 '17 at 7:11
  • It's an oddity: Germans use an English abbreviation (f.e. or f.x.), while English-speakers use a Latin one. Germans naturally assume that the abbreviation they used is also used in English, but it really isn't. – TRiG May 30 '17 at 9:03
  • 1
    @TRiG I don't know one German who uses 'f.e.' or 'f.x.'! I (and every other German I know) use 'bspw.'. – Skillmon May 30 '17 at 11:15
11

The problem is, that your \temp in the tried fix is read as one token and not parsed correctly. Inserting a few \expandafters fixes this:

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}
\usepackage{xstring}

\NewDocumentCommand{\Int}{ >{\SplitList{;}}o}{%
    \IfValueT{#1}{\ProcessList{#1}{\IntLimitONE}}\,%
}
\NewDocumentCommand{\IntLimitONE}{m}{%
    \IfSubStr{#1}{*}{\StrSubstitute{#1}{*}{}[\temp]\oint\expandafter\IntSplitLimits\expandafter{\temp}}{\int\IntSplitLimits{#1}}
}
\NewDocumentCommand{\IntSplitLimits}{ >{\SplitArgument{1}{,}}m}{%
    \IfValueT{#1}{\IntLimits#1}%
}
\NewDocumentCommand{\IntLimits}{mm}{%
    _{#1}^{\IfNoValueTF{#2}{}{#2\!\!}}%
}

\begin{document}
  \begin{equation}
     \Int[a,b;*c,d;e,f] f(x,y,z) dxdydz \quad , \quad \Int[*a,b] f(x) dx
  \end{equation}
\end{document}

enter image description here

  • This does work as intended, even if you misplace * [a*,b] :) – Simon May 29 '17 at 21:31
  • @SimonJensen well it is your fix not mine. I just inserted the \expandafters. – Skillmon May 30 '17 at 6:51
10

The outer part is good.

For deciding whether * appears, I use \SplitArgument for at most one occurrence of *; this will produce two arguments, the second of which is -NoValue- in case no asterisk appears.

The rest is just splitting at the comma.

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}

\NewDocumentCommand{\Int}{>{\SplitList{;}}O{}}{%
  \ProcessList{#1}{\IntA}%
}
\NewDocumentCommand{\IntA}{>{\SplitArgument{1}{*}}{m}}{%
  \IntB#1%
}
\NewDocumentCommand{\IntB}{mm}{%
  \IfNoValueTF{#2}
   {\IntC{\int}{#1}}% no *
   {\IntC{\oint}{#2}}% *
}
\NewDocumentCommand{\IntC}{m >{\SplitArgument{1}{,}}m}{%
  \IntD{#1}#2%
}
\NewDocumentCommand{\IntD}{mmm}{%
  #1_{#2}^{#3}%
}

\begin{document}

\begin{equation}
\Int[a,b;*c,d;e,f] f(x,y,z) \,dx\,dy\,dz \quad , \quad \Int[*a,b] f(x)\,dx
\end{equation}

\end{document}

enter image description here

With expl3 functions, you can split the argument at ; and map on the sequence so obtained. If the item starts with *, discard it and choose \oint, otherwise choose \int.

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\Int}{O{}}
 {
  \simon_int:n { #1 }
 }

\seq_new:N \l_simon_int_args_seq

\cs_new_protected:Nn \simon_int:n
 {
  \seq_set_split:Nnn \l_simon_int_args_seq { ; } { #1 }
  \seq_map_inline:Nn \l_simon_int_args_seq
   {
    \str_if_eq_x:nnTF { \tl_head:n { ##1 } } { * }
     {% * case
      \simon_int_inner:Nf \oint { \tl_tail:n { ##1 } }
     }
     {% no * case
      \simon_int_inner:Nn \int { ##1 }
     }
   }
 }
\cs_new_protected:Nn \simon_int_inner:Nn
 {
  #1 \sb{ \clist_item:nn { #2 } { 1 } }
     \sp{ \clist_item:nn { #2 } { 2 } }
 }
\cs_generate_variant:Nn \simon_int_inner:Nn { Nf }
\ExplSyntaxOff

\begin{document}

\begin{equation}
\Int[a,b;*c,d;e,f] f(x,y,z) \,dx\,dy\,dz \quad , \quad \Int[*a,b] f(x)\,dx
\end{equation}

\end{document}

A variant that checks for the asterisk even if not leading the item:

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\Int}{O{}}
 {
  \simon_int:n { #1 }
 }

\seq_new:N \l__simon_int_args_seq
\tl_new:N \l__simon_int_ast_tl

\cs_new_protected:Nn \simon_int:n
 {
  \seq_set_split:Nnn \l__simon_int_args_seq { ; } { #1 }
  \seq_map_inline:Nn \l__simon_int_args_seq
   {
    \tl_if_in:nnTF { ##1 } { * }
     {% * case
      \tl_set:Nn \l__simon_int_ast_tl { ##1 }
      \tl_remove_once:Nn \l__simon_int_ast_tl { * }
      \simon_int_inner:NV \oint \l__simon_int_ast_tl
     }
     {% no * case
      \simon_int_inner:Nn \int { ##1 }
     }
   }
 }
\cs_new_protected:Nn \simon_int_inner:Nn
 {
  #1 \sb{ \clist_item:nn { #2 } { 1 } }
     \sp{ \clist_item:nn { #2 } { 2 } }
 }
\cs_generate_variant:Nn \simon_int_inner:Nn { NV }
\ExplSyntaxOff

\begin{document}

\begin{equation}
\Int[a,b;*c,d;e*,f] f(x,y,z) \,dx\,dy\,dz \quad , \quad \Int[*a,b] f(x)\,dx
\end{equation}

\end{document}

enter image description here

  • +1 I often upvote your excellent answer. I like the retina screenshot. :-) – Sebastiano May 29 '17 at 20:38
  • 2
    It's no fun if you come around the corner and outsmart my answers by far :) – Skillmon May 29 '17 at 20:54
  • @Skillmon Nice attempt, but never mix xstring with xparse. ;-) And the second version just defines two functions (plus a user level one) instead of four. – egreg May 29 '17 at 21:12
  • This works quite well, except if you misplace *, that I can live with :) – Simon May 29 '17 at 21:28
  • @SimonJensen The second code can be quite easily adjusted to check for a * anywhere. – egreg May 29 '17 at 21:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.