为 latex 中的现有环境分配更多参数

为 latex 中的现有环境分配更多参数

我有一个如下的 .tex 文件

\begin{Solution}
A
\end{Solution}
\begin{Solution}
B
\end{Solution}
\begin{Solution}
A
\end{Solution}
\begin{Solution}
A
\end{Solution}
\begin{Solution}
B
\end{Solution}
\begin{Solution}
B
\end{Solution}
\begin{Solution}
A
\end{Solution}
\begin{Solution}
A
\end{Solution}
\begin{Solution}
C
\end{Solution}
\begin{Solution}
B
\end{Solution}
\begin{Solution}
B
\end{Solution}
\begin{Solution}
A
\end{Solution}

我想使用文章类(或书籍)和答案包(或其他东西)来创建一个宏,编译后得到一个像这样的.tex 文件:

\begin{Solution}{1}
A
\end{Solution}
\begin{Solution}{2}
B
\end{Solution}
\begin{Solution}{3}
A
\end{Solution}
\begin{Solution}{4}
A
\end{Solution}
\begin{Solution}{5}
B
\end{Solution}
\begin{Solution}{6}
B
\end{Solution}
\begin{Solution}{7}
A
\end{Solution}
\begin{Solution}{8}
A
\end{Solution}
\begin{Solution}{9}
C
\end{Solution}
\begin{Solution}{10}
B
\end{Solution}
\begin{Solution}{11}
B
\end{Solution}
\begin{Solution}{12}
A
\end{Solution}

希望大家自助!

答案1

似乎您有一个带有一系列环境的 .tex 文件Solution

从中您希望派生出另一个 .tex 文件,其中Solution-environments 在环境名称后面有一个参数,用于提供连续编号。

(我认为这些数字可能是名义数字(与基数或序数相反),以便环境的每个实例Solution都有一个其唯一名称的参数,例如,可以将其传递给环境定义\label内的命令。Solution

此外,我假设您有两个文档的序言/框架。
对于其中一个序言/框架,环境Solution被定义为不处理任何参数。
您有一个 .tex 文件,可以通过 加载\input,其中Solution-environment 的实例符合该定义。
对于另一个序言/框架,环境Solution被定义为处理一个参数。
对于您的 .tex 文件,您需要调整Solution-environment 的实例,以便它们可以与其他框架一起使用。
因此,需要在每个序列后面附加一个表示(名义)数字的参数\begin{Solution}。)

我认为 TeX 不是最好的工具。有些编辑器/命令行工具可以用正则表达式进行搜索和替换。

如果您坚持使用 (La)TeX:LaTeX3/expl3 有一些不错的正则表达式工具。LuaTeX 引擎提供了很好的工具,可以在将内容传递到传统的“TeX 消化道”之前对其进行预处理。

作为一个穷人的方法我可以提供一个文件来用 LaTeX 进行编译,它不提供文档,但提供用于创建另一个 .tex 文件的副本的脚本/命令,以便在该 .tex 文件的副本中对Solution环境进行连续编号。命令是:

\CopyFileAndAppendNumberToPhraseBeginSolution{⟨source-file⟩}{⟨target-file⟩}

副本⟨源文件⟩⟨目标文件⟩,附加在每个实例后面,以便在{⟨number⟩}\begin{Solution}⟨目标文件⟩这些实例按顺序编号,从 1 开始,在⟨目标文件⟩事情看起来是这样的:。\begin{Solution}{⟨number⟩}

“穷人的方法”因为

  • 构成整个内容的所有标记⟨目标文件⟩在写入之前,会在宏参数中累积。这限制了文件大小。
  • 短语必须与此完全相同。和\begin{Solution}之间不能有空格或换行符。 不能有类似的东西\begin{Solution}
    \begin{So%
    lu%
    %%%%
    tion}
  • 编号总是从 1 开始。
  • Solution在 -environments内部嵌套-environmentsSolution则不予考虑。
  • 事实上,可能存在\begin{Solution}不需要在短语后附加编号的地方,或者编号不应该连续而应该重复的地方,例如,在 -command 的参数内\verb,或在verbatim- 或listings-environment 内,这些都没有被考虑在内。
  • TeX 的一个固有属性是行右端的空格字符(ASCII 和 unicode 中的代码点编号均为 32)将始终被删除。这在 TeX 对 .tex 输入行进行预处理时就已经发生,甚至在标记化之前,因此对此无能为力。
    如果您使用任何编辑软件创建了以空格字符结尾的行的 .tex 输入文件,则无法使用 TeX 创建该文件的精确副本:副本中将缺少这些空格字符。
  • 在写入目标文件/副本时,TeX 可能会对某些字符产生 ^^-notation。
  • 在源文件中\begin{Solution}通过 ^^ 符号写入短语的单个字符不予考虑。
  • 例如,通过宏来隐藏事物则\def\foobar{Solution}...\begin{\foobar}...\end{\foobar}不予考虑。
  • ...
%------------------------------------------------------------------------------
%
% Just to make sure you have an external .tex-file which can be used as
%  <source-file> when applying 
% \CopyFileAndAppendNumberToPhraseBeginSolution{<source-file>}{<target-file>}
% let's create a file testA.tex in the current directory via the
% filecontents*-environment:

\begin{filecontents*}{testA.tex}
\begin{Solution}
A
\end{Solution}
\begin{Solution}
B
\end{Solution}
\begin{Solution}
A
\end{Solution}
\begin{Solution}
A
\end{Solution}
\begin{Solution}
B
\end{Solution}
\begin{Solution}
B
\end{Solution}
\begin{Solution}
A
\end{Solution}
\begin{Solution}
A
\end{Solution}
\begin{Solution}
C D
\end{Solution}
\begin{Solution}
B
\end{Solution}
\begin{Solution}
B
\end{Solution}
\begin{Solution}
A
\end{Solution}
\end{filecontents*}

%------------------------------------------------------------------------------

%  Now let's create a script providing a command
%
%  \CopyFileAndAppendNumberToPhraseBeginSolution{<source-file>}{<target-file>}
%
%  which copies <source-file> to <target-file>, appending {<number>} behind
%  each instance of \begin{Solution}, so that these instances are numbered
%  consecutively, starting with number 1.

\makeatletter
%%=============================================================================
%% PARAPHERNALIA:
%% \UD@firstoftwo, \UD@secondoftwo, \UD@PassFirstToSecond, \UD@Exchange,
%% \UD@stopromannumeral, \UD@CheckWhetherNull,
%% \UD@CheckWhetherLeadingExplicitSpace, \UD@checkstringsubsetof,
%% \UD@Scratchwrite
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\newcommand\UD@Exchange[2]{#2#1}%
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
\newwrite\UD@Scratchwrite
%%-----------------------------------------------------------------------------
%% 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}%
}%
%%-----------------------------------------------------------------------------
%% Check whether brace-balanced argument starts with a space-token
%%.............................................................................
%% \UD@CheckWhetherLeadingExplicitSpace{<Argument which is to be checked>}%
%%                                     {<Tokens to be delivered in case <argument
%%                                       which is to be checked> does have a
%%                                       leading explicit space-token>}%
%%                                     {<Tokens to be delivered in case <argument
%%                                       which is to be checked> does not have a
%%                                       a leading explicit space-token>}%
\newcommand\UD@CheckWhetherLeadingExplicitSpace[1]{%
  \romannumeral\UD@CheckWhetherNull{#1}%
  {\expandafter\UD@stopromannumeral\UD@secondoftwo}%
  {%
    % Let's nest things into \UD@firstoftwo{...}{} to make sure they are nested in braces
    % and thus do not disturb when the test is carried out within \halign/\valign:
    \expandafter\UD@firstoftwo\expandafter{%
      \expandafter\expandafter\expandafter\UD@stopromannumeral
      \romannumeral\expandafter\UD@secondoftwo
      \string{\UD@CheckWhetherLeadingExplicitSpaceB.#1 }{}%
    }{}%
  }%
}%
\@ifdefinable\UD@CheckWhetherLeadingExplicitSpaceB{%
  \long\def\UD@CheckWhetherLeadingExplicitSpaceB#1 {%
    \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
    {\UD@Exchange{\UD@firstoftwo}}{\UD@Exchange{\UD@secondoftwo}}%
    {\expandafter\expandafter\expandafter\UD@stopromannumeral
     \expandafter\expandafter\expandafter}%
     \expandafter\UD@secondoftwo\expandafter{\string}%
  }%
}%
%%===============================================================================
%% Check if string of non-special character-tokens can be obtained by
%% truncating characters from the right side of another string or is equal to
%% other string:
%%===============================================================================
%% \UD@CheckWhetherStringCanBeObtainedByRightTruncating{<possible substring>}{<string>}%
%%   {<tokens if <possible substring> and <string> are equal>}%
%%   {<tokens if <possible substring> can be obtained by right-side-truncating characters from <string>>}%
%%   {<tokens if <possible substring> can not be obtained by right-side-truncating haracters from c<string>>}}%
%% The length of <possible substring> must not exceed the length of <string>!!!
\newcommand\UD@CheckWhetherStringCanBeObtainedByRightTruncating[5]{%
  \UD@CheckWhetherStringCanBeObtainedByRightTruncatingloop#1\relax#2\relax{{#3}{#4}}{#5}%
}%
\@ifdefinable\UD@CheckWhetherStringCanBeObtainedByRightTruncatingloop{%
  \def\UD@CheckWhetherStringCanBeObtainedByRightTruncatingloop#1#2\relax#3#4\relax{%
    \if\string#1\string#3\expandafter\UD@firstoftwo\else\expandafter\UD@secondoftwo\fi
    {%
      \ifx\relax#2\relax\expandafter\UD@firstoftwo\else\expandafter\UD@secondoftwo\fi
      {%
        \ifx\relax#4\relax\expandafter\UD@firstoftwo\else\expandafter\UD@secondoftwo\fi
        {\expandafter\UD@firstoftwo\UD@firstoftwo}{\expandafter\UD@secondoftwo\UD@firstoftwo}%
      }%
      {\UD@CheckWhetherStringCanBeObtainedByRightTruncatingloop#2\relax#4\relax}%
    }{\expandafter\UD@secondoftwo}%
  }%
}%
%%=============================================================================
\newcommand\CopyFileAndAppendNumberToPhraseBeginSolution[2]{%
  % #1 source file  #2 target file
  \IfFileExists{"./#1"}{%
     \UD@PassFirstToSecond{%
        \begingroup
        \let\do\@makeother % <- this and the next line switch to
        \dospecials        %    verbatim-category-code-régime.
        \do\^^I%
        \do\^^M%
        \begingroup
        \everyeof{{XX}}%
        \begingroup
        \def\tempa{\endgroup\filereadandreplaceloop{1}{#2}{}{}}%
        \expandafter\tempa\@@input "./#1" %
        \endgroup
     }%
  }{%
     \@latex@warning@no@line{Source-file `#1' does not exist in the\MessageBreak
                             current directory. Copying aborted}%
     \UD@PassFirstToSecond{}%
  }%
  {\IfFileExists{"./#2"}{%
     \@latex@warning@no@line{Target-file `#2' already exists in the\MessageBreak
                             current directory. Not generating it from this source}%
  }}%
}%
\begingroup
\def\filereadandreplaceloop#1#2#3#4{%
  % #1 = catcode-12-character-token-string  "\begin{Solution}"
  % #2 = catcode-12-return/^^M
  % #3 = catcode-12-{
  % #4 = catcode-12-}
  \endgroup
  \@ifdefinable\UD@@trimtrailingendl{%
    \long\def\UD@@trimtrailingendl##1#2\UD@seldom##2\UD@SELDOM##3{%
      \UD@CheckWhetherNull{##2}{\UD@stopromannumeral##3}{\UD@stopromannumeral##1}%
    }%
  }%
  \newcommand\UD@trimtrailingendl[1]{%
    \romannumeral\UD@@trimtrailingendl##1\UD@seldom#2\UD@seldom\UD@SELDOM{##1}%
  }%
  \newcommand\filereadandreplaceloop[5]{%
    % ##1 = solution-number
    % ##2 = target-file
    % ##3 = text of target-file gathered so far
    % ##4 = Part of phrase \begin{Solution} gathered so far
    % ##5 = next character of source-file or XX
    \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}##5}{%
      \expandafter\UD@CheckWhetherLeadingExplicitSpace\expandafter{\string##5}%
                                          {\filereadandreplaceloopb{##1}{##2}{##3}{##4}{##5}}%
                                          {\expandafter\UD@PassFirstToSecond\expandafter{\string##5}{\filereadandreplaceloopb{##1}{##2}{##3}{##4}}}%
    }{%
      \endgroup
      % Write ##3##4 to target-file ##2
      \@latex@warning@no@line{Writing file `./##2' to the current directory}%
      \begingroup
      \newlinechar=`\^^M %
      \immediate\openout\UD@Scratchwrite="./##2" %
      \immediate\write\UD@Scratchwrite{\UD@trimtrailingendl{##3##4}}%
      \immediate\closeout\UD@Scratchwrite
      \endgroup
    }%
  }%
  \newcommand\filereadandreplaceloopb[5]{%
    % ##1 = solution-number
    % ##2 = target-file
    % ##3 = text of target-file gathered so far
    % ##4 = Part of phrase \begin{Solution} gathered so far
    % ##5 = next character of source-file as catcode-12-character
    \UD@CheckWhetherStringCanBeObtainedByRightTruncating{##4##5}{#1}{%
      %<tokens if <possible substring> and <string> are equal>
       \expandafter\filereadandreplaceloop\expandafter{\number\numexpr##1+1\relax}{##2}{##3##4##5#3##1#4}{}%
    }{%
      %<tokens if <possible substring> can be obtained by right-side-truncating characters from <string>>
      \filereadandreplaceloop{##1}{##2}{##3}{##4##5}%
    }{%
       %<tokens if <possible substring> can not be obtained by right-side-truncating haracters from c<string>>%
       \filereadandreplaceloop{##1}{##2}{##3##4##5}{}%
    }%
  }%
}%
% ======================================================================
% Temporarily change the catcode-régime and call
% \filereadandreplaceloop to close the group and redefine itself:
% ======================================================================
\def\@makeotherrecursion#1{%
  \ifx\@makeotherrecursion#1\else\@makeother#1\relax\expandafter\@makeotherrecursion\fi
}%
\UD@firstoftwo{%
  \@makeotherrecursion\\\b\e\g\i\n\{\S\o\l\u\t\i\o\n\}\^^M\@makeotherrecursion
  \catcode`\[=1
  \catcode`\]=2
  \filereadandreplaceloop
}{}[\begin{Solution}][^^M][{][}]%
\makeatother

%------------------------------------------------------------------------------

%  Now let's test the command defined in the script:

\CopyFileAndAppendNumberToPhraseBeginSolution{testA.tex}{testB.tex}%

\stop

-environmentfilecontents*创建一个文件测试A.tex如下所示:

\begin{Solution}
A
\end{Solution}
\begin{Solution}
B
\end{Solution}
\begin{Solution}
A
\end{Solution}
\begin{Solution}
A
\end{Solution}
\begin{Solution}
B
\end{Solution}
\begin{Solution}
B
\end{Solution}
\begin{Solution}
A
\end{Solution}
\begin{Solution}
A
\end{Solution}
\begin{Solution}
C D
\end{Solution}
\begin{Solution}
B
\end{Solution}
\begin{Solution}
B
\end{Solution}
\begin{Solution}
A
\end{Solution}

该命令\CopyFileAndAppendNumberToPhraseBeginSolution{testA.tex}{testB.tex}%创建一个文件测试B.tex如下所示:

\begin{Solution}{1}
A
\end{Solution}
\begin{Solution}{2}
B
\end{Solution}
\begin{Solution}{3}
A
\end{Solution}
\begin{Solution}{4}
A
\end{Solution}
\begin{Solution}{5}
B
\end{Solution}
\begin{Solution}{6}
B
\end{Solution}
\begin{Solution}{7}
A
\end{Solution}
\begin{Solution}{8}
A
\end{Solution}
\begin{Solution}{9}
C D
\end{Solution}
\begin{Solution}{10}
B
\end{Solution}
\begin{Solution}{11}
B
\end{Solution}
\begin{Solution}{12}
A
\end{Solution}

Solution文件中环境的语法测试A.texSolution与文件中环境的语法不同测试B.tex

因此,Solution当时的环境定义\input测试A.tex必须与Solution当时环境的定义不同\input测试B.tex

相关内容