2

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?

1
  • @UlrichDiez LaTeX
    – zmkm
    Apr 2, 2022 at 0:49

3 Answers 3

5

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/}%
4
  • 1
    I prefer the second example, because you don't need to manually list all the files. But what if the .tex files are located in a different folder, say if main.tex is 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 2, 2022 at 0: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}}% \fi means
    – zmkm
    Apr 2, 2022 at 1:12
  • thank you, I will open a new question
    – zmkm
    Apr 2, 2022 at 2:16
  • Let us continue this discussion in chat.
    – zmkm
    Apr 2, 2022 at 2:34
2

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.

2

In OpTeX, we can do this:

\fornum 1..45 \do {\input{#1.tex}}
\bye

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .