例如
我有两个具有相似文件名结构的 TeX 项目:
master.tex 的结构如下:
\input{preamble.tex} % <- \bibliography{Projekt_A_Literature} in preamble
% ...
\begin{document}
% ...
\include{chapter/Projekt_A_cp1.tex}
\include{chapter/Projket_A_cp2.tex}
\include{chapter/Projekt_A_cp3.tex}
% ...
\end{document}
目的是:我可以轻松、快速地更改要输入的章节文件组。
\include{chpater/Project_A_cp1.tex} \include{chpater/Project_B_cp1.tex}
\include{chpater/Project_A_cp2.tex} ==> \include{chpater/Project_B_cp2.tex}
\include{chapter/Project_A_cp3.tex} \include{chpater/Project_B_cp3.tex}
一个简单但不优雅的方法是:
\newcommand{\prjindex}{A} $ or \def\prjindex{A}
%...
\begin{document}
\include{chpater/Project_\prjindex_cp1.tex}
\include{chpater/Project_\prjindex_cp2.tex}
\include{chpater/Project_\prjindex_cp3.tex}
\end{document}
这个解决方案的问题是,如果我不在主 TeX 文件中进行编译,它会给出如下错误
未定义的控制序列....{Project_\prjindex_Literature.tex}。
所以我来这里是为了寻找一个更优雅的解决方案
答案1
似乎您需要一种在没有“手动”提供\prjindex
定义的情况下进行自动检测的“机制” 。\prjindex
初步说明:
通常原始的扩展\jobname
形成了用于启动编译的文件的名称(不带扩展名)。
例如,如果你编译一个项目,其主文件是testfile.tex
通过命令行执行的
latex testfile.tex
,则原语\jobname
将扩展为短语testfile
。
由传递的短语中的字符标记\jobname
将始终属于类别代码 12(其他),而空格将始终属于类别代码 10(空格)。
testfile
扩展的短语\jobname
将用于
- 创建 .log 文件: .log 文件将被命名为
testfile.log
。 - 创建主 .aux 文件:该文件将被命名为
testfile.aux
。 - 创建保存目录数据的.toc 文件:该文件将被命名为
testfile.toc
。 - 创建保存图表列表数据的 .lof 文件:该文件将被命名为
testfile.lof
。 - 创建保存表格列表数据的 .lot 文件:该文件将被命名为
testfile.lot
。 - ETC。
但现在大多数 TeX 发行版都可以使用 (La)TeX偏离通常的处理方式:
如今,在大多数 TeX 发行版中,您可以在命令行提供一个命令行选项(-option ‑‑jobname
),它可以让您更改要传递的短语\jobname
。
testfile.tex
例如,如果您通过命令行编译其主文件的项目
latex --jobname=foobar testfile.tex
,则原语\jobname
将扩展为短语foobar
。
foobar
在这种情况下,来自扩展的短语\jobname
将用于
- 创建 .log 文件: .log 文件将被命名为
foobar.log
。 - 创建主 .aux 文件:该文件将被命名为
foobar.aux
。 - 创建保存目录数据的.toc 文件:该文件将被命名为
foobar.toc
。 - 创建保存图表列表数据的 .lof 文件:该文件将被命名为
foobar.lof
。 - 创建保存表格列表数据的 .lot 文件:该文件将被命名为
foobar.lot
。 - ETC。
以下是我的建议,要求 LaTeX 处理以下事情在里面通常方式即需要编译的东西没有提供一些‑‑jobname
-选项。
因此,我下面的建议不适合使用此类(在线)LaTeX 平台/TeX 编辑器/用户界面的人,在这些界面下,一切都被配置为使用 -option ‑‑jobname
。
以防万一
- 在编译过程中,所有文件的名称
\prjindex
都是“自动检测”的(因为不会“手动”定义),它们都是有模式的—既表示项目,又不为空,也不包含下划线()—Projekt_⟨#1⟩_⟨#2⟩.tex
⟨#1⟩
_
\prjindex
调用 latex 进行“独立编译”文件,在编译过程中始终会进行“自动检测”的定义没有调用‑‑jobname
-option(这意味着 -primitive 的扩展\jobname
形成了用于启动编译的文件的名称(不带扩展名))
\GetPrjindexFromJobnameIfUndefined
,其作用如下:
如果宏\prjindex
已经定义,它什么也不做。
如果\prjindex
未定义该宏,它将检查\jobname
-primitive 的扩展是否符合模式。 如果不是该模式,则会触发错误消息。 如果符合该模式,它将检查 是否为空。 如果是,则会触发错误消息。 如果不是,则将定义宏以扩展为。Projekt_⟨#1⟩_⟨#2⟩
⟨#1⟩
\prjindex
⟨#1⟩
我无法决定该例程是否对您有用,因为您没有详细透露项目文件结构的那部分是如何组织的,这使得可以编译单个文件,既可以“独立”编译,也可以通过或从主 tex 文件调用。Projekt_⟨#1⟩_⟨#2⟩.tex
\input
\include
如果所有项目文件以某种方式共享相同的前导码,您可能可以通过该前导码使该例程可供所有项目文件使用。
也许你可以把这个例程(以及对它的调用)包含到你的这个例程中,如果已经定义,preamble.tex.
那么这个例程什么也不做。 因此\prjindex
- 你
master.tex
可以定义\prjindex
前输入中preamble.tex
。 - 独立编译其中一个文件的场景会导致输入尚未定义的内容,而这又会导致例程“自动检测”并通过检查扩展的结果为您定义。
Projekt_⟨#1⟩_⟨#2⟩.tex
\preamble.tex
\prjindex
\GetPrjindexFromJobnameIfUndefined
\prjindex
\jobname
\documentclass{article}
%%========Code for \GetPrjindexFromJobnameIfUndefined=========
\begingroup
\makeatletter
\def\prjprephrase{Projekt_}%
\def\prjpostphrase{_}%
% \jobname delivers everything but the space (which will be of catcode 10)
% with catcode 12(other). Therefore "sanitizing" is needed for turning
% everything but the space into catcode 12(other):
\@onelevel@sanitize\prjprephrase
\@onelevel@sanitize\prjpostphrase
\newcommand\GetPrjindexFromJobnameIfUndefined[2]{%
\endgroup
\newcommand\GetPrjindexFromJobnameIfUndefined{%
\@ifundefined{prjindex}{%
\expandafter\GetPrjindexCheckPattern\jobname$#1#2$&%
}{}%
}%
\@ifdefinable\GetPrjindexCheckPattern{%
\def\GetPrjindexCheckPattern##1#1##2#2##3$##4&{%
\GetPrjindexPatternfork
&##4&{\expandafter\GetPrjindexExtractfrompattern\jobname$}%
#2$&{%
\GenericError{(\string\prjindex)\space}{%
Error on input line \the \inputlineno:\MessageBreak
\string\GetPrjindexFromJobnameIfUndefined\space cannot extract the\MessageBreak
\string\prjindex\space from \string\jobname's expansion.\MessageBreak
(\string\GetPrjindexFromJobnameIfUndefined\space is defined\MessageBreak
\space somewhere in this document.)\@gobble
}{Have a look at the comments in this document.}%
{%
\string\GetPrjindexFromJobnameIfUndefined\space can extract the \string\prjindex\MessageBreak
from \string\jobname's expansion only in case \string\jobname's expansion is\MessageBreak
of pattern\MessageBreak
\@spaces #1\string####1#2\string####2\MessageBreak
while \string####1 is not empty.\MessageBreak
If this is the case, the expansion of \string\prjindex\space will be \string####1.\MessageBreak
\string####1 will not contain underscores (\string_).\MessageBreak
\string####2 can contain underscores.\MessageBreak
}%
}%
&&&&%
}%
}%
\@ifdefinable\GetPrjindexPatternfork{%
\def\GetPrjindexPatternfork##1#2$&##2##3&&&&{##2}%
}%
\@ifdefinable\GetPrjindexExtractfrompattern{%
\def\GetPrjindexExtractfrompattern#1##1#2##2${%
\ifx\relax##1\relax
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
{%
\GenericError{(\string\prjindex)\space}{%
Error on input line \the \inputlineno:\MessageBreak
\string\prjindex\space is empty.\MessageBreak
(\string\GetPrjindexFromJobnameIfUndefined\space is defined\MessageBreak
\space somewhere in this document.)\@gobble
}{Have a look at the comments in this document.}%
{%
\string\GetPrjindexFromJobnameIfUndefined\space can extract the \string\prjindex\MessageBreak
from \string\jobname's expansion only in case \string\jobname's expansion is\MessageBreak
of pattern\MessageBreak
\@spaces #1\string####1#2\string####2\MessageBreak
while \string####1 is not empty.\MessageBreak
If this is the case, the expansion of \string\prjindex\space will be \string####1.\MessageBreak
\string####1 will not contain underscores (\string_).\MessageBreak
\string####2 can contain underscores.\MessageBreak
}%
}%
{\newcommand*\prjindex{##1}}%
}%
}%
}%
\expandafter\expandafter\expandafter\GetPrjindexFromJobnameIfUndefined
\expandafter\expandafter\expandafter{\expandafter\prjprephrase\expandafter}%
\expandafter{\prjpostphrase}%
%%=====End of code for \GetPrjindexFromJobnameIfUndefined=====
\GetPrjindexFromJobnameIfUndefined
\show\prjindex
\begin{document}
Some document
\end{document}
顺便说一句:为了测试例程,我将上面的示例保存为test.tex
并对其进行了编译,‑‑jobname
并使用不同的值调用了-option。
通过命令进行编译latex test.tex
得到预期结果:
! Error on input line 80:
(\prjindex) \GetPrjindexFromJobnameIfUndefined cannot extract the
(\prjindex) \prjindex from \jobname's expansion.
(\prjindex) (\GetPrjindexFromJobnameIfUndefined is defined
(\prjindex) somewhere in this document.)
Have a look at the comments in this document.
Type H <return> for immediate help.
...
l.80 \GetPrjindexFromJobnameIfUndefined
?
> \prjindex=undefined.
l.82 \show\prjindex
这是意料之中的,因为在这种情况下,\jobname
扩展为test
不符合模式。
Projekt_⟨#1⟩_⟨#2⟩
通过命令进行编译latex ‑‑jobname=Projekt_A_4 test.tex
得到预期结果:
\prjindex=macro:
->A.
l.82 \show\prjindex
(当将示例保存为Projekt_A_4.tex
并通过命令编译时,您将获得相同的结果latex Projekt_A_4.tex
。)
通过命令进行编译latex ‑‑jobname=Projekt_B_4 test.tex
得到预期结果:
\prjindex=macro:
->B.
l.82 \show\prjindex
(当将示例保存为Projekt_B_4.tex
并通过命令编译时,您将获得相同的结果latex Projekt_B_4.tex
。)
通过命令进行编译latex ‑‑jobname=Projekt_JohannGambolputty_12345 test.tex
得到预期结果:
\prjindex=macro:
->JohannGambolputty.
l.82 \show\prjindex
(当将示例保存为Projekt_JohannGambolputty_12345.tex
并通过命令编译时,您将获得相同的结果latex Projekt_JohannGambolputty_12345.tex
。)
顺便一提:
有时我会按如下方式组织我的项目文件:
序言.tex
% Check whether the \documentclass-command was already invoked.
% If so, increment \inputlevel and stop inputting.
% If not so, don't stop imputting and thus do all the
% preamble-stuff, inclusive defining \inputlevel:
\expandafter\ifx\csname @twoclasseserror\endcsname\documentclass
\xdef\inputlevel{\number\numexpr\inputlevel+1\relax}%
\expandafter\endinput
\fi
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\documentclass{article}%
%
\newcommand*\inputlevel{1}%
\global\let\inputlevel=\inputlevel
%
% Whatsoever preamble-commands, etc.
%
% Here you can also place the code for defining \GetPrjindexFromJobnameIfUndefined
% and then invoke it for defining \prjindex:
%
%%========Code for \GetPrjindexFromJobnameIfUndefined=========
\begingroup
\makeatletter
\def\prjprephrase{Projekt_}%
\def\prjpostphrase{_}%
% \jobname delivers everything but the space (which will be of catcode 10)
% with catcode 12(other). Therefore "sanitizing" is needed for turning
% everything but the space into catcode 12(other):
\@onelevel@sanitize\prjprephrase
\@onelevel@sanitize\prjpostphrase
\newcommand\GetPrjindexFromJobnameIfUndefined[2]{%
\endgroup
\newcommand\GetPrjindexFromJobnameIfUndefined{%
\@ifundefined{prjindex}{%
\expandafter\GetPrjindexCheckPattern\jobname$#1#2$&%
}{}%
}%
\@ifdefinable\GetPrjindexCheckPattern{%
\def\GetPrjindexCheckPattern##1#1##2#2##3$##4&{%
\GetPrjindexPatternfork
&##4&{\expandafter\GetPrjindexExtractfrompattern\jobname$}%
#2$&{%
\GenericError{(\string\prjindex)\space}{%
Error on input line \the \inputlineno:\MessageBreak
\string\GetPrjindexFromJobnameIfUndefined\space cannot extract the\MessageBreak
\string\prjindex\space from \string\jobname's expansion.\MessageBreak
(\string\GetPrjindexFromJobnameIfUndefined\space is defined\MessageBreak
\space somewhere in this document.)\@gobble
}{Have a look at the comments in this document.}%
{%
\string\GetPrjindexFromJobnameIfUndefined\space can extract the \string\prjindex\MessageBreak
from \string\jobname's expansion only in case \string\jobname's expansion is\MessageBreak
of pattern\MessageBreak
\@spaces #1\string####1#2\string####2\MessageBreak
while \string####1 is not empty.\MessageBreak
If this is the case, the expansion of \string\prjindex\space will be \string####1.\MessageBreak
\string####1 will not contain underscores (\string_).\MessageBreak
\string####2 can contain underscores.\MessageBreak
}%
}%
&&&&%
}%
}%
\@ifdefinable\GetPrjindexPatternfork{%
\def\GetPrjindexPatternfork##1#2$&##2##3&&&&{##2}%
}%
\@ifdefinable\GetPrjindexExtractfrompattern{%
\def\GetPrjindexExtractfrompattern#1##1#2##2${%
\ifx\relax##1\relax
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
{%
\GenericError{(\string\prjindex)\space}{%
Error on input line \the \inputlineno:\MessageBreak
\string\prjindex\space is empty.\MessageBreak
(\string\GetPrjindexFromJobnameIfUndefined\space is defined\MessageBreak
\space somewhere in this document.)\@gobble
}{Have a look at the comments in this document.}%
{%
\string\GetPrjindexFromJobnameIfUndefined\space can extract the \string\prjindex\MessageBreak
from \string\jobname's expansion only in case \string\jobname's expansion is\MessageBreak
of pattern\MessageBreak
\@spaces #1\string####1#2\string####2\MessageBreak
while \string####1 is not empty.\MessageBreak
If this is the case, the expansion of \string\prjindex\space will be \string####1.\MessageBreak
\string####1 will not contain underscores (\string_).\MessageBreak
\string####2 can contain underscores.\MessageBreak
}%
}%
{\newcommand*\prjindex{##1}}%
}%
}%
}%
\expandafter\expandafter\expandafter\GetPrjindexFromJobnameIfUndefined
\expandafter\expandafter\expandafter{\expandafter\prjprephrase\expandafter}%
\expandafter{\prjpostphrase}%
%%=====End of code for \GetPrjindexFromJobnameIfUndefined=====
%
% This will define \prjindex depending on the expansion of \jobname
% while \jobname usually represents the name of the file used for
% initiating compilation:
%
% !!! I don't know whether, e.g., online-latex-plattforms like overleaf
% !!! invoke latex using the -jobname-option, which would lead to
% !!! the expansion of \jobname deviating from the name of the file
% !!! used for initiating compilation.
%
\GetPrjindexFromJobnameIfUndefined
%
% With subsequent preamble-commands you can, if you wish, fork depending on
% the expansion of \prjindex. But be aware that like \jobname \prjindex also
% holds only characters of catcode 12(other) and spaces of catcode 10(space).
% Therefore when storing a string in a temporary macro (this should, like
% \prjindex not be defined in terms of \long, which is the case with
% \def or \newcommand*) and \ifx-comparing that temporary macro to \prjindex,
% make sure that the definition of that temporary macro is "sanitized" by
% means of \@onelevel@sanitize before doing the \ifx-comparison.
%
% \usepackage...
% \usepackage...
%
\begin{document}%
\endinput
|
| Place whatsoever comments remarks and explanations and manuals you wish to place
| here. They won't be processed because LaTeX ceases reading and processing this
| file when encountering \endinput.
后记.tex
\csname @\ifnum\inputlevel>1 second\else first\fi oftwo\endcsname
{%
\end{document}%
}{%
\xdef\inputlevel{\number\numexpr\inputlevel-1\relax}%
}%
项目_A_cp1.tex
%----------------------
\input{Preamble.tex}%
%----------------------
This is file \texttt{Projekt\string_A\string_cp1.tex}\par
This is the text in file \texttt{Projekt\string_\prjindex\string_cp1.tex}.\par
The file \texttt{Projekt\string_\prjindex\string_cp1.tex} invokes the file \texttt{Projekt\string_\prjindex\string_cp2.tex}:\par
\input{Projekt_\prjindex_cp2.tex}%
%----------------------
\input{Postamble.tex}%
%----------------------
项目_A_cp2.tex
%----------------------
\input{Preamble.tex}%
%----------------------
This is file \texttt{Projekt\string_A\string_cp2.tex}\par
This is the text in file \texttt{Projekt\string_\prjindex\string_cp2.tex}.\par
The file \texttt{Projekt\string_\prjindex\string_cp2.tex} invokes the file \texttt{Projekt\string_\prjindex\string_cp3.tex}:\par
\input{Projekt_\prjindex_cp3.tex}%
%----------------------
\input{Postamble.tex}%
%----------------------
项目_A_cp3.tex
%----------------------
\input{Preamble.tex}%
%----------------------
This is file \texttt{Projekt\string_A\string_cp3.tex}\par
This is the text in file \texttt{Projekt\string_\prjindex\string_cp3.tex}.\par
%----------------------
\input{Postamble.tex}%
%----------------------
项目_B_cp1.tex
%----------------------
\input{Preamble.tex}%
%----------------------
This is file \texttt{Projekt\string_B\string_cp1.tex}\par
This is the text in file \texttt{Projekt\string_\prjindex\string_cp1.tex}.\par
The file \texttt{Projekt\string_\prjindex\string_cp1.tex} invokes the file \texttt{Projekt\string_\prjindex\string_cp2.tex}:\par
\input{Projekt_\prjindex_cp2.tex}%
%----------------------
\input{Postamble.tex}%
%----------------------
项目_B_cp2.tex
%----------------------
\input{Preamble.tex}%
%----------------------
This is file \texttt{Projekt\string_B\string_cp2.tex}\par
This is the text in file \texttt{Projekt\string_\prjindex\string_cp2.tex}.\par
The file \texttt{Projekt\string_\prjindex\string_cp2.tex} invokes the file \texttt{Projekt\string_\prjindex\string_cp3.tex}:\par
\input{Projekt_\prjindex_cp3.tex}%
%----------------------
\input{Postamble.tex}%
%----------------------
项目_B_cp3.tex
%----------------------
\input{Preamble.tex}%
%----------------------
This is file \texttt{Projekt\string_B\string_cp3.tex}\par
This is the text in file \texttt{Projekt\string_\prjindex\string_cp3.tex}.\par
%----------------------
\input{Postamble.tex}%
%----------------------
这样,每个文件、、Projekt_A_cp1.tex
分别 都可用于 “独立”编译,也可通过或由同一项目的另一个文件调用。Projekt_A_cp2.tex
Projekt_A_cp3.tex
Projekt_B_cp1.tex
Projekt_B_cp2.tex
Projekt_B_cp3.tex
\input
\include
Preamble.tex
可以包含根据 的含义发生分叉的代码\prjindex
,因此可以针对同一前言文件内的不同项目以不同的方式处理事情。
答案2
我不确定问题是什么,但你肯定需要对你的代码进行更改:\include
必须的参数不是有.tex
扩展名。
\documentclass{book}
% why shouldn't this be elegant
\newcommand{\projectindex}{B}
\begin{document}
\include{chapter/Project_\projectindex_cp1}
\include{chapter/Project_\projectindex_cp2}
\include{chapter/Project_\projectindex_cp3}
\end{document}
这是编译此代码时的终端输出
pdflatex sun
This is pdfTeX, Version 3.14159265-2.6-1.40.20 (TeX Live 2019) (preloaded format=pdflatex)
restricted \write18 enabled.
entering extended mode
(./sun.tex
LaTeX2e <2019-10-01> patch level 3
(/usr/local/texlive/2019/texmf-dist/tex/latex/base/book.cls
Document Class: book 2019/10/25 v1.4k Standard LaTeX document class
(/usr/local/texlive/2019/texmf-dist/tex/latex/base/bk10.clo)) (./sun.aux
(./chapter/Project_B_cp1.aux) (./chapter/Project_B_cp2.aux)
(./chapter/Project_B_cp3.aux)) (./chapter/Project_B_cp1.tex
Chapter 1.
) [1{/usr/local/texlive/2019/texmf-var/fonts/map/pdftex/updmap/pdftex.map}]
(./chapter/Project_B_cp2.tex [2]
Chapter 2.
) [3] (./chapter/Project_B_cp3.tex [4]
Chapter 3.
) [5] (./sun.aux (./chapter/Project_B_cp1.aux) (./chapter/Project_B_cp2.aux)
(./chapter/Project_B_cp3.aux)) )</usr/local/texlive/2019/texmf-dist/fonts/type1
/public/amsfonts/cm/cmbx12.pfb></usr/local/texlive/2019/texmf-dist/fonts/type1/
public/amsfonts/cm/cmr10.pfb></usr/local/texlive/2019/texmf-dist/fonts/type1/pu
blic/amsfonts/cm/cmsl10.pfb>
Output written on sun.pdf (5 pages, 30009 bytes).
如果我改为\newcommand{\projectindex}{A}
,在运行两次 LaTeX 后我得到
pdflatex sun
This is pdfTeX, Version 3.14159265-2.6-1.40.20 (TeX Live 2019) (preloaded format=pdflatex)
restricted \write18 enabled.
entering extended mode
(./sun.tex
LaTeX2e <2019-10-01> patch level 3
(/usr/local/texlive/2019/texmf-dist/tex/latex/base/book.cls
Document Class: book 2019/10/25 v1.4k Standard LaTeX document class
(/usr/local/texlive/2019/texmf-dist/tex/latex/base/bk10.clo)) (./sun.aux
(./chapter/Project_A_cp1.aux) (./chapter/Project_A_cp2.aux)
(./chapter/Project_A_cp3.aux)) (./chapter/Project_A_cp1.tex
Chapter 1.
) [1{/usr/local/texlive/2019/texmf-var/fonts/map/pdftex/updmap/pdftex.map}]
(./chapter/Project_A_cp2.tex [2]
Chapter 2.
) [3] (./chapter/Project_A_cp3.tex [4]
Chapter 3.
) [5] (./sun.aux (./chapter/Project_A_cp1.aux) (./chapter/Project_A_cp2.aux)
(./chapter/Project_A_cp3.aux)) )</usr/local/texlive/2019/texmf-dist/fonts/type1
/public/amsfonts/cm/cmbx12.pfb></usr/local/texlive/2019/texmf-dist/fonts/type1/
public/amsfonts/cm/cmr10.pfb></usr/local/texlive/2019/texmf-dist/fonts/type1/pu
blic/amsfonts/cm/cmsl10.pfb>
Output written on sun.pdf (5 pages, 29893 bytes).
Transcript written on sun.log.
如您所见,预期的文件已包含在内。