我正在尝试跟随这个答案根据文件系统层次结构自动包含文件。
我的文件结构如下:
article.tex
sections/
|-- 00-introductions.tex
|-- 10-data.tex
|-- 20-analysis.tex
|-- 90-conclusions.tex
|-- data/
| |-- 00-xxx.tex
| |-- NN-xxx.tex
|
|-- analysis/
|-- 00-xxx.tex
|-- NN-xxx.tex
因此,我想将 中的所有内容、 中的所有内容以及 中的所有内容都包括在内sections
。就article.tex
这个问题而言,我们只关注。sections/data
10-data.tex
sections/analysis
20-analysis.tex
article.tex
为了尝试遵循链接的答案,我创建了以下 bash 脚本来生成适当文件的列表:
#! /bin/bash
ls -mp sections/ | grep -v / | tr ' ' '\n' > sections.list
我已将其添加到我的,.latexmkrc
以便它在每个版本上运行(这部分有效)。它输出以下内容(如果相关,则有新行):
00-introduction.tex,
10-data.tex,
20-analysis.tex,
30-conclusions.tex,
我还尝试了不添加逗号的替代方法。
我的articles.tex
(无意义的)看起来像这样:
\documentclass[twocolumn, a4paper]{article}
\usepackage{pgffor}
\newcommand*{\listofsections}{\input{sections.list}}
\begin{document}
\foreach \c in \listofsections {%
\input{sections/\c}%
}%
\end{document}
如果我只是输出\listofsections
它对我来说看起来很好:
看起来好像我的循环定义出了问题,因为日志中出现了这些错误:
/home/james/repos/discos-paper/article.tex:28: 缺少插入的 endcsname。 let l.28 } % /home/james/repos/discos-paper/article.tex:28: ??? 的使用与其定义不符。 ???
!LaTeX3 错误:文件名中的 let 无效。 丢失:reserved@d =... l.28 } % /home/james/repos/discos-paper/article.tex:28: 缺少插入的 endcsname。 let l.28 } % /home/james/repos/discos-paper/article.tex:28: ??? 的使用与其定义不符。 ???
!LaTeX3 错误:文件名中的 let 无效。 丢失:reserved@d =... l.28 } % /home/james/repos/discos-paper/article.tex:28: 缺少插入的 endcsname。 let l.28 } % /home/james/repos/discos-paper/article.tex:28: ??? 的使用与其定义不符。???
! LaTeX3 错误:文件名中的 let 无效。丢失:reserved@d =... l.28 } %!LaTeX 错误:未找到文件“sections/.tex”。
我在这里遗漏了什么?
编辑1:
出于某种原因,似乎我的 \listofsections 作为单个项目通过,并且迭代器仅被调用一次......
我现在也尝试编辑列表文件如下:
00-introduction.tex,10-data.tex,20-analysis.tex,30-conclusions.tex
它仍然不起作用,即使我把它放在里面也不起作用,\newcommand
但奇怪的是,如果我将内容直接复制到 foreach 循环中它也会起作用...所以说实话,我真的不确定出了什么问题。
答案1
如果sections.list
每行有一个文件名(没有逗号)
00-introduction.tex
10-data.tex
20-analysis.tex
30-conclusions.tex
您可以一次读取一行来获取文件名,然后输入:
\documentclass{article}
\newread\sections
\openin\sections=sections.list
\begin{document}
\loop
{\endlinechar=-1 \global\read\sections to \next}
\ifx\next\empty\else
\input{\next}
\repeat
\end{document}
答案2
我不认为那\foreach
是正确的工具,因为它以组的形式执行循环中的每个项目。
您不是将其定义\listofsections
为列表,而是定义为输入文件的命令。
\begin{filecontents*}{\jobname-sections.list}
00-introduction.tex,
10-data.tex,
20-analysis.tex,
30-conclusions.tex,
\end{filecontents*}
\documentclass[twocolumn, a4paper]{article}
\usepackage{pgffor}
\usepackage{catchfile}
\CatchFileDef{\listofsections}{\jobname-sections.list}{}
\begin{document}
\foreach \c in \listofsections {%
\if\relax\c\relax
\else
%\input{sections/\c}%
I would input ``sections/\c''\endgraf
\fi
}
\end{document}
我更改了名称只是为了使“tryout”文件夹中的文件名保持可区分,并使用了“mock \input
”来显示发生了什么。这\if\relax\c\relax
是为了避免出现虚假的最终输入。
我喜欢的方式是
\begin{filecontents*}{\jobname-sections.list}
00-introduction.tex,
10-data.tex,
20-analysis.tex,
30-conclusions.tex,
\end{filecontents*}
\documentclass[twocolumn, a4paper]{article}
\ExplSyntaxOn
\NewDocumentCommand{\inputfromlist}{m}
{% #1 is the name of the file containing the list
% store the contents of the file in \l_tmpa_tl
\file_get:nnN { #1 } { } \l_tmpa_tl
% transform the tl into a clist
\clist_set:NV \l_tmpa_clist \l_tmpa_tl
% cycle through the items i the list
\clist_map_inline:Nn \l_tmpa_clist
{
%\input{##1}
I~would~input~``sections/##1''\par
}
}
\ExplSyntaxOff
\begin{document}
\inputfromlist{\jobname-sections.list}
\end{document}
该函数\file_get:nnN
是expl3
的模拟函数\CatchFileDef
。然后我将内容转换为 clist(空项将自动删除)并映射它。
做什么\clist_set:NV \l_tmpa_clist \l_tmpa_tl
?它与
\clist_set:Nn \l_tmpa_clist { <contents of \l_tmpa_tl> }
该\clist_set:Nn
函数进行规范化,因此删除空项(即由零个或多个空格组成)。
最后,该\clist_map_inline:Nn
函数循环遍历列表的项目。当前项目用 表示#1
,但由于我们位于命令的定义中,因此必须使用##1
。
答案3
如果不使用软件包来执行此操作,我可能会让 TeX 切换到 verbatim-catcode-régime,\endlinechar
表示回车符的代码点编号,并通过可扩展输入文件列表\@@input
并将其处理为回车符分隔的参数列表。
(传统 TeX 的内部字符编码方案是 ASCII。LuaTeX 和 XeTeX 的内部字符编码方案是 unicode,而 ASCII 是其严格子集。回车符的代码点数在 ASCII 和 unicode 中都是 13。在 .tex 输入文件中,回车符可以在 TeX 的^^
-notation 中通过表示^^M
;M 是拉丁字母中的第^^
13 个字母。 -notation 要求将类别代码 7(上标)分配给字符^
,这是默认值。)
这样文件名就按照逐字逐句的编码规则读取。如果文件名包含空格字符序列和/或诸如等字符,则这可能是一个功能^
,这些字符通常/可能被 TeX 以特殊方式处理,或者(如{
和}
)在宏参数(如宏的参数)中出现时需要平衡\input
。
\futurelet
仅用于确保 TeX 向前看,并据此删除文件末尾的 eof 标记,否则file ended while scanning the use of...
在抓取标记循环末尾的\inputfileloop
最后一个/附加的-dummy-line 时可能会触发 -error。(或者,也可以使用它来附加最后一个 dummy-line。)\relax
\everyeof
\begin{filecontents*}{\jobname_inputfiles.txt}
00-introduction.tex
10-data.tex
20-analysis.tex
30-conclusions.tex
40-weird}%} {^#^^61^^!.tex
\end{filecontents*}
\documentclass{article}
\begingroup
\makeatletter\endlinechar=-1\relax\catcode`\^^M=12 %
\@firstofone{%
\endgroup
\NewDocumentCommand\inputfiles{mv}{%
\begingroup
\let\do\@makeother\dospecials\do\^^M\do\^^I%
%\endlinechar=`\^^M\relax %<- This is the default, thus this line is turned into a comment.
\def\temp{\inputfileloop{}{#2}}%
\expandafter\futurelet\expandafter\tempb\expandafter\temp\@@input "#1" \relax^^M%
}%
\@ifdefinable\inputfileloop{%
% recursively in #1 accumulate a list of \input-commands
% #1 list of \input-commands gathered so far
% #2 directory
% #3 filename or \relax-token to process in this iteration.
\long\def\inputfileloop#1#2#3^^M{%
\ifx\relax#3\expandafter\@secondoftwo\else\expandafter\@firstoftwo\fi
% Use this for inputting:
%{\def\temp{\inputfileloop{#1\input{#2#3}}{#2}}\futurelet\tempb\temp}{\endgroup#1}%
% Use this for message on terminal instead of inputting:
{\def\temp{\inputfileloop{#1\message{I would \string\input{#2#3}^^J}}{#2}}\futurelet\tempb\temp}{\endgroup#1}%
}%
}%
}%
\begin{document}
\inputfiles{\jobname_inputfiles.txt}{section/}
\end{document}
终端上的消息为:
I would \input{section/00-introduction.tex}
I would \input{section/10-data.tex}
I would \input{section/20-analysis.tex}
I would \input{section/30-conclusions.tex}
I would \input{section/40-weird}%} {^#^^61^^!.tex}
对于最后一条消息,-command 的参数\input
是:(
section/section/40-weird}%}␣␣{^#^^61^^!.tex
表示␣
空格字符。)
形成该参数的标记序列在逐字分类代码机制下被标记化,因此
- 多个空间不会合并成一个空间。
^^
-notation 被禁用,即^^61^^!
未被标记为aa
{
并且}
不被视为用于确定范围/表示参数的括号,而是被视为普通字符。#
被视为普通字符,可以在从其参数定义临时宏的宏的参数中不加倍使用。%
被视为普通字符
我刚刚想到,当处理包含输入文件列表的文件时,您可能希望产生空行:
% Let's within the current directory/folder create the file holding
% the list of input-files:
\begin{filecontents*}{\jobname_inputfiles.txt}
00-introduction.tex
10-data.tex
20-analysis.tex
30-conclusions.tex
mysubsection/40-bla.tex
50-weird}%} {^#^^61^^!.tex
\end{filecontents*}
\documentclass{article}
\begingroup
\makeatletter\endlinechar=-1\relax\catcode`\^^M=12 %
\@firstofone{%
\endgroup
\NewDocumentCommand\inputfiles{mv}{%
\begingroup
\let\do\@makeother\dospecials\do\^^M\do\^^I%
%\endlinechar=`\^^M\relax %<- This is the default, thus this line is turned into a comment.
\def\temp{\inputfileloop{}{#2}}%
\expandafter\futurelet\expandafter\tempb\expandafter\temp\@@input "#1" \relax^^M%
}%
\@ifdefinable\inputfileloop{%
% recursively in #1 accumulate a list of \input-commands
% #1 list of \input-commands gathered so far
% #2 directory; slash etc needs to be included so you can leave it empty if you like.
% #3 filename or \relax-token to process in this iteration.
\long\def\inputfileloop#1#2#3^^M{%
\ifx\relax#3\expandafter\@secondoftwo\else\expandafter\@firstoftwo\fi
{%
\def\temp{%
\ifcat$\detokenize{#3}$\expandafter\@gobble\else\expandafter\inputfileappendtolist\fi
{#3}\inputfileloop{#1}{#2}%
}%
\futurelet\tempb\temp
}{\endgroup#1}%
}%
}%
\newcommand\inputfileappendtolist[4]{%
#2{#3%
% Use this for inputting:
%\input{#4#1}%
% Use this for message on terminal instead of inputting:
\message{I would \string\input{#4#1}^^J}%
}{#4}%
}%
}
\begin{document}
\inputfiles{\jobname_inputfiles.txt}{mysection/}
\end{document}
终端上的消息为:
I would \input{mysection/00-introduction.tex}
I would \input{mysection/10-data.tex}
I would \input{mysection/20-analysis.tex}
I would \input{mysection/30-conclusions.tex}
I would \input{mysection/mysubsection/40-bla.tex}
I would \input{mysection/50-weird}%} {^#^^61^^!.tex}
对于最后一条消息,-command 的参数\input
是:(
mysection/50-weird}%}␣␣{^#^^61^^!.tex
表示␣
空格字符。)