Suppose I am writing a book with 45 chapters (in separate files 1.tex 2.tex etc) and I want to input them into main.tex. How can I write a for loop for this?
- 379
-
@UlrichDiez LaTeX – zmkm Apr 02 '22 at 00:49
3 Answers
As it is about inputting files containing chapters of a LaTeX-document I suppose the \include-command is the appropriate command for inputting files. But you can easily replace instances of \include by instances of \input if you prefer.
Edit: As a leftover from when I switched from \input to \include, I erroneously left the filename-extension ".tex" as ⟨tokens after number-component of filename⟩. Unlike with \input with \include you don't provide the extension .tex—the extension .tex is added automatically by the \include-command. This is now rectified.
Probably a tail-recursive loop does the trick.
Here a loop where filenames are specified:
\newcommand\noneofone[1]{}%
\newcommand\firstofone[1]{#1}%
\newcommand\includeloop[2]{%
\ifx\relax#2\expandafter\noneofone\else\expandafter\firstofone\fi
{\include{#1#2}\includeloop{#1}}%
}%
\includeloop{./chapters/}{filename1}{filename2}{filename3}{filename4}{filename5}%
{filename6}{filename7}{filename8}{filename9}{filename10}%
{filename11}{filename12}{filename13}{filename14}{filename15}%
{filename16}{filename17}{filename18}{filename19}{filename20}%
{filename21}{filename22}{filename23}{filename24}{filename25}%
{filename26}{filename27}{filename28}{filename29}{filename30}%
{filename31}{filename32}{filename33}{filename34}{filename35}%
{filename36}{filename37}{filename38}{filename39}{filename40}%
{filename41}{filename42}{filename43}{filename44}{filename45}\relax
In case all filenames are of same pattern, you can have a loop based on counting:
Syntax:
\includepatternloop{⟨lower bound of number range⟩}%
{⟨upper bound of number range⟩}%
{⟨tokens before number-component of filename⟩}%
{⟨tokens after number-component of filename⟩}%
{⟨directory/file-path⟩}%
yields a sequence of
\include{%
⟨directory/file-path⟩%
⟨tokens before number-component of filename⟩%
⟨number-component of filename⟩%
⟨tokens after number-component of filename⟩%
}
The code
\newcommand\exchange[2]{#2#1}%
\newcommand\includepatternloop[5]{%
\include{#5#3#1#4}%
\ifnum#1<\expandafter\exchange\expandafter{\number#2}{} %
\exchange{\expandafter\includepatternloop\expandafter{\number\numexpr#1+1\relax}{#2}{#3}{#4}{#5}}%
\fi
}%
\includepatternloop{1}{45}{File}{of45Files}{./chapters/}%
gets you a sequence:
\include{./chapters/File1of45Files}%
\include{./chapters/File2of45Files}%
...
\include{./chapters/File45of45Files}%
If you don't want \ifnum#1<\expandafter\exchange\expandafter{\number#2}{} % you can introduce another macro which applies \number for normalizimg things before actually starting the loop:
\newcommand\exchange[2]{#2#1}%
\newcommand\includepatternloop[2]{%
\expandafter\exchange\expandafter{\expandafter{\number#2}}{\includepatternloopinternal{#1}}%
}%
\newcommand\includepatternloopinternal[5]{%
\include{#5#3#1#4}%
\ifnum#1<#2 %
\exchange{\expandafter\includepatternloopinternal\expandafter{\number\numexpr#1+1\relax}{#2}{#3}{#4}{#5}}%
\fi
}%
\includepatternloop{1}{45}{File}{of45Files}{./chapters/}%
- 28,770
-
1I prefer the second example, because you don't need to manually list all the files. But what if the
.texfiles are located in a different folder, say ifmain.texis in./and chapters in directory./chapters/how can I modify the loop? TBH I don't understand how the loop works, but it does work! – zmkm Apr 02 '22 at 00:57 -
Can you explain what
\ifnum#1<\expandafter\exchange\expandafter{\number#2}{} % \exchange{\expandafter\includepatternloop\expandafter{\number\numexpr#1+1\relax}{#2}{#3}{#4}{#5}}% \fimeans – zmkm Apr 02 '22 at 01:12 -
-
You can define a generic loop over a range of numbers to do various tasks.
\documentclass{article}
\ExplSyntaxOn
\NewDocumentCommand{\genericloop}{mmm}
{
\zmkm_genericloop:nnn { #1 } { #2 } { #3 }
}
\cs_new_protected:Nn __zmkm_genericloop_task:n { } % initialize
\cs_new_protected:Nn \zmkm_genericloop:nnn
{
\cs_set_protected:Nn __zmkm_genericloop_task:n { #3 }
\int_step_function:nnN { #1 } { #2 } __zmkm_genericloop_task:n
}
\ExplSyntaxOff
\begin{document}
\genericloop{1}{45}{\input{./chapters/#1.tex}}
\end{document}
The idea is to use \int_step_function:nnN that repeats the execution of the scratch function \__zmkm_genericloop_task:n for each number in the range specified by the first and second argument. The third argument to \genericloop is the template to use, where #1 stands for the current number in the loop.
For checking that everything works, I reproduce the console output with
\genericloop{1}{10}{\typeout{\string\input{./chapters/#1.tex}}
We get
\input{./chapters/1.tex}
\input{./chapters/2.tex}
\input{./chapters/3.tex}
\input{./chapters/4.tex}
\input{./chapters/5.tex}
\input{./chapters/6.tex}
\input{./chapters/7.tex}
\input{./chapters/8.tex}
\input{./chapters/9.tex}
\input{./chapters/10.tex}
What if the chapters have numbers 01.tex to 09.tex and then 10.tex and so on? We can define a “padding” function.
\documentclass{article}
\ExplSyntaxOn
\NewExpandableDocumentCommand{\padding}{mm}
{
\prg_replicate:nn { #1-\str_count:n { #2 } } { 0 } #2
}
\NewDocumentCommand{\genericloop}{mmm}
{
\zmkm_genericloop:nnn { #1 } { #2 } { #3 }
}
\cs_new_protected:Nn __zmkm_genericloop_task:n { } % initialize
\cs_new_protected:Nn \zmkm_genericloop:nnn
{
\cs_set_protected:Nn __zmkm_genericloop_task:n { #3 }
\int_step_function:nnN { #1 } { #2 } __zmkm_genericloop_task:n
}
\ExplSyntaxOff
\begin{document}
\genericloop{1}{10}{\typeout{\string\input{./chapters/\padding{2}{#1}.tex}}}
\end{document}
The console output would be
\input{./chapters/01.tex}
\input{./chapters/02.tex}
\input{./chapters/03.tex}
\input{./chapters/04.tex}
\input{./chapters/05.tex}
\input{./chapters/06.tex}
\input{./chapters/07.tex}
\input{./chapters/08.tex}
\input{./chapters/09.tex}
\input{./chapters/10.tex}
Of course you'll call
\genericloop{1}{45}{\input{./chapters/\padding{2}{#1}.tex}}
if you want to input 01.tex up to 45.tex.
- 1,121,712