如何制作一个命令来自动创建类似素数分解的乘积?

如何制作一个命令来自动创建类似素数分解的乘积?

我经常发现自己输入的产品中每个术语看起来都很相似,但下标被替换了。我想创建一个可以自动执行此操作的命令,语法如下

\replaceproduct{general term}{write first _ terms}{end with index at}

例如,对数字 N 进行质因数分解,如下所示

可以排版为

\replaceproduct{p_i^{\epsilon_i}}{3}{n}

我不确定这样的命令是否可行,并且我心中有疑虑(特别是关于命令如何知道索引变量 - 它可能必须是另一个参数,并且我不确定命令如何区分 \epsilon 中的 i 和 p_i 中的 i),但我对 LaTeX 不是很有经验。

答案1

我尝试expl3使用l3regex

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand\replaceproduct
  { 
    O { i }
    m
    O { \cdots }
    m
  }
  {
    \seq_set_from_clist:Nn \l_tmpa_seq { #4 }
    \seq_map_inline:Nn \l_tmpa_seq
      {
        \tl_set:Nn \l_tmpa_tl { #2 }
        \tl_if_blank:nTF { ##1 }
        { #3 }
        {
          \regex_replace_all:nnN { #1 } { \cB\{ ##1 \cE\} } \l_tmpa_tl
          \tl_use:N \l_tmpa_tl
        }
      }
  }
\ExplSyntaxOff

\begin{document}

\(\replaceproduct{p_i^{\epsilon_i}}{1,2,3,{},n}\)

\end{document}

我使用的语法与你要求的略有不同。因为不会有很多术语(我猜),那么我更喜欢这样:

\replaceproduct[<what-to-replace>]{<where-to-replace>}[<empty-item>]{<list-of-things>}

可选参数默认分别为i\cdots。你可以使用以下方式排版:

\( \replaceproduct{p_i^{\epsilon_i}}{1,2,3,{},n} \)

此宏将遍历 ,<list-of-things>并将<what-to-replace>中找到的每个 替换<where-to-replace>为 中的一个项<list-of-things>。如果它找到{},则改用<empty-item>


编辑:

使用您要求的语法:

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand\replaceproduct
  { 
    O { i }
    m
    m
    O { \cdots }
    m
  }
  {
    \int_zero:N \l_tmpa_int
    \seq_set_from_clist:Nn \l_tmpa_seq { #5 }
    \int_do_until:nNnn { \l_tmpa_int } = { #3 }
      {
        \int_incr:N \l_tmpa_int
        \tl_set:Nn \l_tmpa_tl { #2 }
        \regex_replace_all:nnN { #1 } { \cB\{ \c { \int_use:N } \c { \l_tmpa_int } \cE\} } \l_tmpa_tl
        \tl_use:N \l_tmpa_tl
      }
      #4
      \tl_set:Nn \l_tmpa_tl { #2 }
      \regex_replace_all:nnN { #1 } { \cB\{ #5 \cE\} } \l_tmpa_tl
      \tl_use:N \l_tmpa_tl
  }
\ExplSyntaxOff

\begin{document}

\( \replaceproduct{p_i^{\epsilon_i}}{3}{n} \)

\end{document}

使用方式:

\replaceproduct[<what-to-replace>]{<where-to-replace>}{<from-one-to->}[<dots-thingy>]{<last-item>}

答案2

一些有趣的expl3技巧:

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

\ExplSyntaxOn
\NewDocumentCommand{\replaceproduct}{mmmm}
 {% #1 = main terms
  % #2 = exponent
  % #3 = first terms
  % #4 = last term
  \int_step_inline:nn { #3 } { #1\sb{##1}^{#2\sb{##1}} }
  \cdots
  #1\sb{#4}^{#2\sb{#4}}
 }
\NewDocumentCommand{\rp}{O{i}mmm}
 {% #1 = item to substitute
  % #2 = main terms
  % #3 = first terms
  % #4 = last term
  \group_begin:
  \tl_set:Nn \l__cid_rp_term_tl { #2 }
  \regex_replace_all:nnN { #1 } { \cB\{\cP\#1\cE\} } \l__cid_rp_term_tl
  \cs_set:NV \__cid_rp_term:n \l__cid_rp_term_tl
  \int_step_function:nN { #3 } \__cid_rp_term:n
  \cdots
  \__cid_rp_term:n { #4 }
  \group_end:
 }
\tl_new:N \l__cid_rp_term_tl
\cs_generate_variant:Nn \cs_set:Nn { NV }
\ExplSyntaxOff

\begin{document}

\begin{gather}
N = \replaceproduct{p}{\varepsilon}{3}{m} = \replaceproduct{q}{\eta}{3}{n}
\\
N = \rp{p_i^{\varepsilon_i}}{3}{m} = \rp[j]{q_j^{\eta_j}}{3}{m}
\end{gather}

\end{document}

我发现第一个宏更容易输入。在第二个宏中,可选参数是要替换的虚拟变量,第二个实例j仅用作示例。

在此处输入图片描述

第二个宏是如何工作的?正则表达式部分将虚拟变量更改为#1;然后将标记列表作为替换文本传递\__cid_rp_term:n,而替换文本又用于\int_step_function:nN,它将执行从 1 到第二个参数中所述的情况。然后\cdots是最后一个案例。

答案3

这应该可以做到:

\newcommand{\replaceproduct}[4]{%
    \saveexploremode%
    \exploregroups%
    \foreach \i in {1,...,#2}{\StrSubstitute{#1}{#3}{\i}} \ldots \StrSubstitute{#1}{#3}{#4}%
    \restoreexploremode%
}

你必须使用pgfforxstring包才能使其工作

使用示例:

\replaceproduct{p_i^{\epsilon_z}}{5}{z}{n}

第一个参数是通用术语,后跟重复次数,后跟索引占位符(必须是通用术语内的唯一字符序列),最后跟最终索引。

答案4

\documentclass{article}

\makeatletter
%%=============================================================================
%% Paraphernalia:
%%    \UD@firstoftwo, \UD@secondoftwo,
%%    \UD@PassFirstToSecond, \UD@Exchange, \UD@removespace
%%    \UD@CheckWhetherNull, \UD@CheckWhetherBrace,
%%    \UD@CheckWhetherLeadingSpace, \UD@ExtractFirstArg
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\newcommand\UD@Exchange[2]{#2#1}%
\newcommand\UD@removespace{}\UD@firstoftwo{\def\UD@removespace}{} {}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
  \romannumeral0\expandafter\UD@secondoftwo\string{\expandafter
  \UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
  \UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument's first token is a catcode-1-character
%%.............................................................................
%% \UD@CheckWhetherBrace{<Argument which is to be checked>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked has leading
%%                        catcode-1-token>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked has no leading
%%                        catcode-1-token>}%
\newcommand\UD@CheckWhetherBrace[1]{%
  \romannumeral0\expandafter\UD@secondoftwo\expandafter{\expandafter{%
  \string#1.}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
  \UD@firstoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether brace-balanced argument starts with a space-token
%%.............................................................................
%% \UD@CheckWhetherLeadingSpace{<Argument which is to be checked>}%
%%                             {<Tokens to be delivered in case <argument
%%                               which is to be checked>'s 1st token is a
%%                               space-token>}%
%%                             {<Tokens to be delivered in case <argument
%%                               which is to be checked>'s 1st token is not
%%                               a space-token>}%
\newcommand\UD@CheckWhetherLeadingSpace[1]{%
  \romannumeral0\UD@CheckWhetherNull{#1}%
  {\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo}%
  {\expandafter\UD@secondoftwo\string{\UD@CheckWhetherLeadingSpaceB.#1 }{}}%
}%
\newcommand\UD@CheckWhetherLeadingSpaceB{}%
\long\def\UD@CheckWhetherLeadingSpaceB#1 {%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@secondoftwo#1{}}%
  {\UD@Exchange{\UD@firstoftwo}}{\UD@Exchange{\UD@secondoftwo}}%
  {\UD@Exchange{ }{\expandafter\expandafter\expandafter\expandafter
   \expandafter\expandafter\expandafter}\expandafter\expandafter
   \expandafter}\expandafter\UD@secondoftwo\expandafter{\string}%
}%
%%-----------------------------------------------------------------------------
%% Extract first inner undelimited argument:
%%
%%   \UD@ExtractFirstArg{ABCDE} yields  {A}
%%
%%   \UD@ExtractFirstArg{{AB}CDE} yields  {AB}
%%.............................................................................
\newcommand\UD@RemoveTillUD@SelDOm{}%
\long\def\UD@RemoveTillUD@SelDOm#1#2\UD@SelDOm{{#1}}%
\newcommand\UD@ExtractFirstArg[1]{%
  \romannumeral0%
  \UD@ExtractFirstArgLoop{#1\UD@SelDOm}%
}%
\newcommand\UD@ExtractFirstArgLoop[1]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
  { #1}%
  {\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillUD@SelDOm#1}}%
}%
%%=============================================================================
%% \DefineReplacementMacro{<replacement-macro>}%
%%                        {<internal helper-macro>}%
%%                        {<item to replace>}%
%%
%%  defines <replacement-macro> to fetch two arguments,
%%  #1 = <replacement for item to replace>
%%  #2 = <token sequence with item to replace>
%%  , and -- after two expansion-steps to deliver:
%%  <token sequence with all instances of <item to replace> replaced 
%%  by <replacement for item to replace>. >
%%
%% Internally an <internal helper-macro> is needed.
%%
%%  (!!! <replacement-macro> does also replace all pairs of matching 
%%       explicit character tokens of catcode 1/2 by matching braces!!!)
%%-----------------------------------------------------------------------------
\newcommand\DefineReplacementMacro[3]{%
  \newcommand#2{}\long\def#2##1#3{}%
  \newcommand#1[2]{%
    \romannumeral0\UD@ReplaceAllLoop{##2}{##1}{}{#2}{#3}%
  }%
}%
\newcommand\UD@ReplaceAllLoop[5]{%
  \UD@CheckWhetherNull{#1}{ #3}{%
    \UD@CheckWhetherLeadingSpace{#1}{%
       \expandafter\UD@ReplaceAllLoop
       \expandafter{\UD@removespace#1}{#2}{#3 }{#4}{#5}%
    }{%
      \UD@CheckWhetherBrace{#1}{%
        \expandafter\expandafter\expandafter\UD@PassFirstToSecond
        \expandafter\expandafter\expandafter{%
        \expandafter\UD@PassFirstToSecond\expandafter{%
            \romannumeral0\expandafter\UD@ReplaceAllLoop
            \romannumeral0\UD@ExtractFirstArgLoop{#1\UD@SelDOm}{#2}{}{#4}{#5}%
        }{#3}}%
        {\expandafter\UD@ReplaceAllLoop\expandafter{\UD@firstoftwo{}#1}{#2}}%
        {#4}{#5}%
      }{%
       \expandafter\UD@CheckWhetherNoReplacement
       \romannumeral0\UD@ExtractFirstArgLoop{#1\UD@SelDOm}{#1}{#2}{#3}{#4}{#5}%
      }%
    }%
  }%
}%
\newcommand\UD@CheckWhetherNoReplacement[6]{%
  \expandafter\UD@CheckWhetherNull\expandafter{#5#1#6}%
  {%
    \expandafter\UD@ReplaceAllLoop
    \expandafter{\UD@firstoftwo{}#2}{#3}{#4#1}{#5}{#6}%
  }{%
    \expandafter\UD@ReplaceAllLoop
    \expandafter{\UD@firstoftwo{}#2}{#3}{#4#3}{#5}{#6}%
  }%
}%
%%=============================================================================
%% \UD@ReplaceAlli -- Replace all "i" in undelimited Argument:
%%
%%   \UD@ReplaceAlli{<replacement for i>}{<token sequence with i>}
%%   yields  <token sequence with all i replaced by replacement for i>
%%
%%  <replacement for i> may contain i.
%%
%%  (This routine does also replace all pairs of matching explicit 
%%   character tokens of catcode 1/2 by matching braces!!!)
%%
%%  The letter "i" as item to replace is hard-coded.
%%  You cannot replace öetters other than I with this macro.
%%.............................................................................
\DefineReplacementMacro{\UD@ReplaceAlli}{\UD@gobbletoi}{i}%
%%
%%=============================================================================
%% \replaceiandreplicate{<term with i>}%
%%                      {<loop-start-index>}%
%%                      {<loop-end-index>}%
%%                      {<separator>}%
%%                      {<end index>}
%%
%% e.g., 
%%
%%  \replaceiandreplicate{p_i^{\epsilon_i}}{1}{3}{\cdots}{n}
%%.............................................................................
\newcommand\replaceiandreplicate[5]{%
   \romannumeral0\expandafter\expandafter
                 \expandafter            \UD@Exchange
                 \expandafter\expandafter
                 \expandafter{%
                 \UD@ReplaceAlli{#5}{#1}%
   }{%
     \replaceiandreplicateloop{#3}{#2}{#1}#4%
   }%
}%
\newcommand\replaceiandreplicateloop[3]{%
  \ifnum#1<#2 %
    \expandafter\UD@firstoftwo
  \else
   \expandafter\UD@secondoftwo
  \fi
  { }{%
    \expandafter\expandafter
    \expandafter            \UD@Exchange
    \expandafter\expandafter
    \expandafter{%
       \UD@ReplaceAlli{#1}{#3}%
    }{%
      \expandafter\replaceiandreplicateloop
      \expandafter{\number\numexpr\number#1-1\relax}{#2}{#3}%
    }%
  }%
}%

\makeatother

\parindent=0ex

\begin{document}

\begin{verbatim}
$\replaceiandreplicate{p_{i}^{\epsilon_{i}}}{1}{3}{\cdots}{n}$
\end{verbatim}

yields:\bigskip

$\replaceiandreplicate{p_{i}^{\epsilon_{i}}}{1}{3}{\cdots}{n}$

\bigskip\hrule

\begin{verbatim}
$\csname @gobble%
  \expandafter\expandafter
  \expandafter\endcsname
  \replaceiandreplicate{\cdot p_{i}^{\epsilon_{i}}}{-3}{5}{\cdot\;\cdots\;}{n}$
\end{verbatim}

yields:\bigskip

$\csname @gobble%
  \expandafter\expandafter
  \expandafter\endcsname
  \replaceiandreplicate{\cdot p_{i}^{\epsilon_{i}}}{-3}{5}{\cdot\;\cdots\;}{n}$

\bigskip\hrule

\begin{verbatim}
\def\sgn#1{\ifnum0<\number\ifx-#1\else-0#1\fi\else+\fi#1}

$\csname @gobble%
  \expandafter\expandafter
  \expandafter\endcsname
  \replaceiandreplicate{\cdot p_{k\sgn{i}}^{\epsilon_{i}}}{-3}{5}{\cdot\;\cdots\;}{n}$
\end{verbatim}

yields:\bigskip

\def\sgn#1{\ifnum0<\number\ifx-#1\else-0#1\fi\else+\fi#1}

$\csname @gobble%
  \expandafter\expandafter
  \expandafter\endcsname
  \replaceiandreplicate{\cdot p_{k\sgn{i}}^{\epsilon_{i}}}{-3}{5}{\cdot\;\cdots\;}{n}$

\end{document}

在此处输入图片描述

相关内容