\newcommand 中的未定义控制序列仅出现在文档中,而不出现在最低限度可重现的示例中

\newcommand 中的未定义控制序列仅出现在文档中,而不出现在最低限度可重现的示例中

我按照这个例子来了解如何使删除线在多个段落中起作用(其中包含引用,这是许多删除线解决方案的症结所在):

更强大的删除线/划掉线

我已经创建了一个可以工作的最小可重现示例,如下所示。

\documentclass{article}
\usepackage{xcolor}
\usepackage[normalem]{ulem}

\newcommand\deleted[1]{\color{red}\let\helpcmd\sout\parhelp#1\par\relax\relax}
\newcommand\added[1]{\color{blue}\let\helpcmd\parhelp#1\par\relax\relax}
\long\def\parhelp#1\par#2\relax{%
  \helpcmd{#1}\ifx\relax#2\else\par\parhelp#2\relax\fi%
}

\begin{document}

\deleted{
Example deleted section - \cite{abc} Lorem ipsum 

dolor sit amet, consectetur adipiscing elit, sed 

do eiusmod tempor incididunt ut labore et dolore magna aliqua.
}

\added{
Example added section - - \cite{abc} Lorem ipsum 

dolor sit amet, consectetur adipiscing elit, sed 

do eiusmod tempor incididunt ut labore et dolore magna aliqua.
}

\end{document}

在我使用此功能的主要文档中,我得到了这些\usepackage语句,并且我正在复制/粘贴这些\newcommand行和\long\def...行(老实说,我不明白这一行,我从上面引用的 tex/SE 文章中复制了它)。

当我使用时\added{...paragraph text...}出现以下Undefined control sequence错误:

\added #1->\color {blue}\let \helpcmd 
                                      \parhelp #1\par \relax \relax 
l.184     }
           
The control sequence at the end of the top line
of your error message was never \def'ed. If you have
misspelled it (e.g., `\hobx'), type `I' and the correct
spelling (e.g., `I\hbox'). Otherwise just continue,
and I'll forget about whatever was undefined.

我看不出我的文档(主要只是包含一堆\usepackage语句)和这里最低限度可重现的示例之间有什么区别。

答案1

乍一看,人们可能会修复\let定义中的-assignment \added,添加一些范围以防止颜色变化永久存在,并用于\DeclareRobustCommand获得一些稳健性:

\documentclass{article}
\usepackage{xcolor}
\usepackage[normalem]{ulem}

\makeatletter
\DeclareRobustCommand\deleted[1]{{\color{red}\let\helpcmd\sout\parhelp#1\par\relax\relax}}
\DeclareRobustCommand\added[1]{{\color{blue}\let\helpcmd\@firstofone\parhelp#1\par\relax\relax}}
\long\def\parhelp#1\par#2\relax{%
  \helpcmd{#1}\ifx\relax#2\else\par\parhelp#2\relax\fi
}
\makeatother

\begin{document}

\noindent texttexttext

\noindent\deleted{  %<- this space is not removed and not striked
Example deleted section - \cite{abc} Lorem ipsum \par
dolor sit amet, consectetur adipiscing elit, sed

do eiusmod tempor incididunt ut labore et dolore magna aliqua. %<- this space is not removed and striked
}texttexttext

\noindent texttexttext

\noindent\added{   %<- this space is not removed
Example added section - - \cite{abc} Lorem ipsum \par
dolor sit amet, consectetur adipiscing elit, sed 

do eiusmod tempor incididunt ut labore et dolore magna aliqua. %<- this space is not removed
}texttexttext

\end{document}

在此处输入图片描述


第二眼:

下面的代码是为了确保

  • 鲁棒性,
  • \added/参数的前导和尾随空格标记\deleted在水平模式下被保留,但不会被删除,
  • \added在/ space-token的参数中,\deleted仍然形成可丢弃的粘连,而不是段落末尾的“删除线的空白”。
\makeatletter
%%=============================================================================
%% Paraphernalia:
%%    \UD@firstoftwo, \UD@secondoftwo, \UD@Exchange, \UD@PassFirstToSecond,
%%    \UD@stopromannumeral, \UD@CheckWhetherNull, \UD@ExtractFirstParArg,
%%    \UD@TrimLeadingTokens, \UD@TrimTrailingTokens
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@gobbletwo[2]{}%
\newcommand\UD@Exchange[2]{#2#1}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
%%-----------------------------------------------------------------------------
%% 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]{%
  \romannumeral\expandafter\UD@secondoftwo\string{\expandafter
  \UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\UD@stopromannumeral\UD@secondoftwo}{%
  \expandafter\UD@stopromannumeral\UD@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Extract first inner \par-undelimited argument:
%%
%%   \UD@ExtractFirstParArg{A\par B\par C\par D\par E} yields  {A}
%%
%%   \UD@ExtractFirstParArg{{AB}\par C\par D\par E} yields  {{AB}}
%%
%%   \UD@ExtractFirstParArg{AB\par C\par D\par E} yields  {AB}
%%
%%   \UD@ExtractFirstParArg{{AB}} yields  {{AB}}
%%
%%   \UD@ExtractFirstParArg{} yields  {}
%%
%% Due to \romannumeral-expansion the result is delivered after two 
%% expansion-steps/after "hitting" \UD@ExtractFirstParArg with \expandafter
%% twice.
%%
%% Use frozen-\relax as delimiter for speeding things up.
%% I chose frozen-\relax because David Carlisle pointed out in
%% <https://tex.stackexchange.com/a/578877>
%% that frozen-\relax cannot be (re)defined in terms of \outer and cannot be
%% affected by \uppercase/\lowercase.
%%
%% \UD@ExtractFirstParArg's argument may contain frozen-\relax:
%% The only effect is that internally more iterations are needed for
%% obtaining the result.
%%
%%.............................................................................
\@ifdefinable\UD@RemoveFromParTillFrozenrelax{%
  \expandafter\expandafter\expandafter\UD@Exchange
  \expandafter\expandafter\expandafter{%
  \expandafter\expandafter\ifnum0=0\fi}%
  {\long\def\UD@RemoveFromParTillFrozenrelax#1\par#2}{{#1}\par}%
}%
\expandafter\UD@PassFirstToSecond\expandafter{%
  \romannumeral\expandafter
  \UD@PassFirstToSecond\expandafter{\romannumeral
    \expandafter\expandafter\expandafter\UD@Exchange
    \expandafter\expandafter\expandafter{%
    \expandafter\expandafter\ifnum0=0\fi}{\UD@stopromannumeral{{}}#1\par}%
  }{%
    \UD@stopromannumeral\romannumeral\UD@ExtractFirstParArgLoop
  }%
}{%
  \newcommand\UD@ExtractFirstParArg[1]%
}%
\newcommand\UD@ExtractFirstParArgLoop[1]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@gobbletwo#1}%
  {%
    \expandafter\expandafter
    \expandafter\UD@stopromannumeral
    \expandafter\UD@PassFirstToSecond
    \expandafter{%
      \romannumeral
      \expandafter\UD@firstoftwo\expandafter\UD@stopromannumeral
      \UD@firstoftwo#1%
    }{}%
  }%
  {\expandafter\UD@ExtractFirstParArgLoop\expandafter{\UD@RemoveFromParTillFrozenrelax#1}}%
}%
%%-----------------------------------------------------------------------------
%%  \UD@iterateParList{<tokens>}{<\par-separated list>}
%%
%%  Each item of the <\par-separated list> is nested in curly braces before
%%  prepending <tokens> to it. Items are separated by \par.
%%
%%  I tried my best at preventing removal of curly braces.
%%  
%%-----------------------------------------------------------------------------
\@ifdefinable\UD@gobbletopar{\long\def\UD@gobbletopar#1\par{}}%
\newcommand\UD@iterateParList[2]{%
  \romannumeral\UD@iterateparlistloop{#2}{#1}{}{}%
}%
\newcommand\UD@iterateparlistloop[4]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@gobbletopar#1\par}{%  
    \UD@stopromannumeral#4#3#2{#1}%
  }{%
    \expandafter\UD@PassFirstToSecond\expandafter{%
       \romannumeral
       \expandafter\expandafter\expandafter\UD@Exchange
       \expandafter\expandafter\expandafter{%
         \UD@ExtractFirstParArg{#1}%
       }{\UD@stopromannumeral#4#3#2}%
    }{%
      \expandafter\UD@iterateparlistloop\expandafter{\UD@gobbletopar#1}{#2}{\par}%
    }%
  }%
}%
%%-----------------------------------------------------------------------------
%%  "\UD@shifttrailspaces{<tokens>}{STUFF  }"  yields  "<tokens>{STUFF}  "
%%-----------------------------------------------------------------------------
\newcommand\UD@shifttrailspaces[2]{%
  \romannumeral
  \expandafter\UD@Exchange\expandafter{%
    \romannumeral\UD@shifttrailspacesloop{{}}#2\UD@ForBidden/ \UD@ForBidden/\UD@ForBidden/ {{}#2}{#1}{}%
  }\UD@stopromannumeral
}%
\@ifdefinable\UD@shifttrailspacesloop{%
  \long\def\UD@shifttrailspacesloop#1 \UD@ForBidden/#2\UD@ForBidden/ #3#4#5{%
    \UD@CheckWhetherNull{#2}{% no trailing space
      \expandafter\UD@PassFirstToSecond\expandafter{\UD@firstoftwo{}#3}{\UD@stopromannumeral#4}#5%
    }{% trailing space
      \UD@shifttrailspacesloop#1\UD@ForBidden/ \UD@ForBidden/\UD@ForBidden/ {#1}{#4}{#5 }%
    }%
  }%
}%
%%-----------------------------------------------------------------------------
%%  "\UD@shiftleadspaces{<tokens>}{  STUFF}"  yields  "  <tokens>{STUFF}"
%%-----------------------------------------------------------------------------
\@ifdefinable\UD@gobblespace{\UD@firstoftwo{\def\UD@gobblespace}{} {}}%
\newcommand\UD@shiftleadspaces[2]{%
  \romannumeral
  \expandafter\UD@Exchange\expandafter{%
    \romannumeral
    \UD@shiftleadspacesloop\UD@ForBidden/#2\UD@ForBidden/ \UD@ForBidden/\UD@ForBidden/{#2}{#1}{}%
  }\UD@stopromannumeral
}%
\@ifdefinable\UD@shiftleadspacesloop{%
  \long\def\UD@shiftleadspacesloop#1\UD@ForBidden/ #2\UD@ForBidden/\UD@ForBidden/#3#4#5{%
    \UD@CheckWhetherNull{#1}{% Leading space
      \expandafter\UD@Exchange\expandafter{\expandafter{\UD@gobblespace#3}}%
      {\UD@shiftleadspacesloop\UD@ForBidden/#2\UD@ForBidden/\UD@ForBidden/}{#4}{#5 }%
    }{% no leading space
      \UD@stopromannumeral#5#4{#3}%
    }%
  }%
}%
%%-----------------------------------------------------------------------------
\@ifdefinable\deleted{%
  \DeclareRobustCommand\deleted[1]{{\color{red}\ifhmode\null\fi\UD@iterateParList{\UD@shifttrailspaces{\UD@shiftleadspaces{\sout}}}{#1}}}%
}%
\@ifdefinable\added{%
  %\DeclareRobustCommand\added[1]{{\color{blue}\ifhmode\null\fi\UD@iterateParList{\UD@shifttrailspaces{\UD@shiftleadspaces{\@firstofone}}}{#1}}}%
  \DeclareRobustCommand\added[1]{{\color{blue}\ifhmode\null\fi#1}}%
}%
\makeatother

\documentclass{article}
\usepackage{xcolor}
\usepackage[normalem]{ulem}

\begin{document}

\noindent texttexttext

\noindent\deleted{  %<- this space is not removed and not striked
Example deleted section - \cite{abc} Lorem ipsum \par
dolor sit amet, consectetur adipiscing elit, sed

do eiusmod tempor incididunt ut labore et dolore magna aliqua. %<- this space is not removed and not striked
}texttexttext

\noindent texttexttext

\noindent\added{   %<- this space is not removed
Example added section - - \cite{abc} Lorem ipsum \par
dolor sit amet, consectetur adipiscing elit, sed 

do eiusmod tempor incididunt ut labore et dolore magna aliqua. %<- this space is not removed
}texttexttext

\end{document}

在此处输入图片描述

相关内容