我有一个如下的 .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。