有很多.txt
文件,我试图在 Latex 中找出一种方法将所有文件合并*.txt
为一个*.txt
。我想过和\newread
,\newwrite
但我不知道是否有更好的方法或如何开始。它们*.tex
具有相同的结构,它们都用于spreadtab
,但在使用之前spreadtab
,我想过将它们合并。我的第一个想法是使用\input
,但它并不像我想象的那么容易。
答案1
此答案未涵盖合并不同输入编码的文本文件的问题。
下文假设所有源文件都具有相同的输入编码,并且目标文件的输入编码应与源文件的输入编码相同。
作为弗兰已经说过了,你不用 TeX 就可以做到这一点,只需使用 shell 命令即可:
在 Linux 终端上
cat MYfileA.tex MYfileB.tex MYfileC.tex > MYfilesABCmerged.tex
应该可以解决问题。
在 Windows PowerShell(其中cat
是 cmdlet 的别名Get-Content
)中,这也可能起到作用。
在 Windows PowerShell 中,另一种变体可能是:
Get-Content MYfileA.tex,MYfileB.tex,MYfileC.tex | Out-File MYfilesABCmerged.tex
然而,请注意Windows PowerShellOut-File
默认情况下,以 UTF-8 格式(重新)编码它生成的文件,没有字节顺序标记,并且您需要使用参数-Encoding
以不同的编码进行(重新)编码。
在 Windows 命令提示符下
type MYfileA.tex MYfileB.tex MYfileC.tex > MYfilesABCmerged.tex
或
copy MYfileA.tex + MYfileB.tex + MYfileC.tex MYfilesABCmerged.tex
应该可以解决问题。
在任何情况下,例如,当使用通配符*
/时?
,请确保目标文件不在要合并的源文件集中!
如果你坚持使用 LaTeX 来做,你可能可以做如下的事情:
% Create three text files
% =======================
\begin{filecontents*}{MYfileA.tex}
01 file A
02 file A
03 file A
04 file A
05 file A
06 file A
07 file A
08 file A
09 file A
10 file A
\end{filecontents*}
\begin{filecontents*}{MYfileB.tex}
01 file B
02 file B
03 file B
04 file B
05 file B
06 file B
07 file B
08 file B
09 file B
10 file B
\end{filecontents*}
\begin{filecontents*}{MYfileC.tex}
01 file C
02 file C
03 file C
04 file C
05 file C
06 file C
07 file C
08 file C
09 file C
10 file C
\end{filecontents*}
% Code for macro for merging files
% ================================
\makeatletter
\newread\ThisInFile
\newwrite\ThisOutFile
\newcommand\mergefiles[2]{%
%\NewDocumentCommand\mergefiles{vv}{%
\begingroup
\let\do\@makeother
\dospecials % verbatim-category-code-régime.
\do\^^I
\do\^^M
\endlinechar=-1\relax
\newlinechar=-1\relax
\IfFileExists{#2}{%
\@latex@warning@no@line{%
File `\detokenize{#2}' already exists on the system.%
\MessageBreak Not generating it from this source%
}%
}{%
\immediate\openout\ThisOutFile #2
%\immediate\openout\ThisOutFile \string"#2\string"
%\immediate\openout\ThisOutFile "#2"
\@for\ThisInFileName:={#1}\do{%
\expandafter\IfFileExists\expandafter{\ThisInFileName}{%
\immediate\openin\ThisInFile \ThisInFileName\relax
%\immediate\openin\ThisInFile \string"\ThisInFileName\string"\relax
%\immediate\openin\ThisInFile "\ThisInFileName"\relax
\appendthisfileloop
\immediate\closein\ThisInFile
}{%
\@latex@warning@no@line{%
File `\detokenize\expandafter{\ThisInFileName}' not found on the system.%
\MessageBreak Therefore it cannot be included into the merge%
}%
}%
}%
\immediate\closeout\ThisOutFile
}%
\endgroup
}%
\newcommand\appendthisfileloop{%
\ifeof\ThisInFile\else
\immediate\read\ThisInFile to \thisline
\ifx\thisline\empty\ifeof\ThisInFile\expandafter\expandafter\expandafter\@gobble\fi\fi
{%
\immediate\write\ThisOutFile{\detokenize\expandafter{\thisline}}%
%\message{(\detokenize\expandafter{\thisline})}%
}%
\expandafter\appendthisfileloop\fi
}%
\makeatother
% Let's merge the three text files:
% =================================
\mergefiles{MYfileA.tex,MYfileB.tex,MYfileC.tex}{MYfilesABCmerged.tex}%
% Have a document which uses the verbatim-package
% for displaying the file where things are merged:
% ================================================
\documentclass{article}
%\usepackage{xparse}
\usepackage{verbatim}
\begin{document}
\noindent This is the content of file \verb|MYfilesABCmerged.tex|:
\verbatiminput{MYfilesABCmerged.tex}
\end{document}
陷阱/警告
!!!通过上面示例的代码,确保使用宏时\mergefiles
目标文件不会出现在源文件的逗号列表中!!!
(如果源文件之一也是目标文件,则意味着在创建目标文件的过程中,在将其读取为源文件之前会破坏该文件。)
使用宏时,\mergefiles
不会对此实施错误检查。即,\mergefiles
不会检查目标文件是否也出现在源文件的逗号列表中!
使用 TeX/LaTeX 复制文本文件时需要注意的事项:
根据文件名中可能出现的字符,您可能希望使用 LaTeX 格式
\mergefiles
来定义\NewDocumentCommand
类型参数v
(=verbatim)。
对于较旧的 LaTeX 发行版,您可能需要加载包解析为此。
“取决于可能出现的字符”:在此,我想到不匹配的字符,如{
或,}
因为在通常的宏参数/非逐字类型参数中,这些字符只有在匹配的对应项也存在时才会出现。对于 DOS/Windows 中的文件路径,反斜杠用于分隔嵌套目录/文件夹的名称,我想到\
在 TeX 中会引入控制序列标记。我想到不应该扩展/执行的活动字符。... 虽然类别代码为 6(参数),但#
TeX/LaTeX 文件名中出现的哈希通常不是问题 - 除非尝试定义临时宏,这些宏会扩展到不基于\edef
和\unexpanded
/的文件名⟨token-注册⟩。使用 TeX 程序进行操作时,目标文件中总会存在松散的空格字符序列,而源文件中的空格字符序列出现在输入文本文件行的右端。对此您无能为力,因为 TeX 在预处理输入文本文件行的阶段就已经丢弃了这些空格,甚至在查看用于标记事物的类别代码之前。
使用 TeX 程序时,目标文件中的换行符(CR 或 CR+LF 之类的东西)的编码可能与源文件中的换行符编码不同。这是因为文件是逐行处理的,当将一行文本写入目标文件时,换行符标记由 TeX 的写入例程生成。据我所知,现在使用 TeX 发行版(如 TeX Live 或 MiKTeX),您可以在写入文件时指定换行符的编码。更多信息可以在TeX Live 指南—2021/ 在里面MiKTeX 手册修订版 4.2。
当使用 TeX 程序进行操作时,在目标文件中你可能会得到
^^
某些字符的符号 -TeXBook,附录 C:字符代码说:关于字符代码的约定很少被硬编码到 TeX 中:
[...]
(6) 有一个以十六进制形式表示字符 0–255 的特殊约定^^00
-^^ff
^
,在第 8 章中解释。当是 catcode 7 的任何字符时,此约定始终可以作为输入接受。按照此约定生成文本输出仅有的当表示 TeX 安装程序选择不直接输出的代码 ≥ 128 的字符时。^^
例如,在 TeX Live 和 MiKTeX 中,您可以提供文件扩展名为 .tcx 的翻译文件,以指定当 TeX 将它们写入外部文本文件时要用 -notation 表示哪些字符。但我认为,有了最新的 TeX 发行版,您就不需要太担心这个问题了:
例如,TeX Live 指南—2021在章节中说9.1.2 2004:
- 几乎所有格式都允许大多数字符通过“翻译文件”以原样打印cp227.tcx,而不是用符号翻译它们
^^
。具体来说,位置 32–256 的字符,加上制表符、垂直制表符和换页符被视为可打印且不翻译。例外是纯 TeX(仅 32–126 可打印)、ConTeXt(0–255 可打印)和 Ω 相关格式。此默认行为与 TeX Live 2003 中的行为几乎相同,但实现得更清晰,具有更多自定义可能性。请参阅 texmf-dist/doc/web2c/web2c.html#TCX-文件(顺便说一下,使用 Unicode 输入,TeX 在显示错误上下文时可能会输出部分字符序列,因为它是面向字节的。)
例如,2000 年 12 月,如今已过时的MiKTeX 手册修订版 2.0在章节中说5.7 TCX 文件:字符翻译:
默认情况下,不会翻译任何字符,并且 32 到 126(含)之间的字符代码(十进制)是可打印的。无法使这些(或任何)字符不可打印。
(我没有在当前版本中找到有关“字符翻译”默认设置的任何声明MiKTeX 手册修订版 4.2。也许我只是忽略了这些。如果是这样,我很高兴得到提示,这样我就可以编辑这个答案。)
- 几乎所有格式都允许大多数字符通过“翻译文件”以原样打印cp227.tcx,而不是用符号翻译它们
关于文件名/目录路径:
当在要由 TeX 程序处理的代码中指定文件名时(例如,在 LaTeX 文档中或 LaTeX 包的 .sty 文件中等等),您需要处理特定于正在使用的平台/shell/操作系统/文件系统的特殊性。
- 例如,需要读取要合并的文件的权限,还需要创建/写入具有合并内容的目标文件的权限。
"
例如,在 MiKTeX 和 TeX Live 中,如果文件名/文件路径包含空格字符,则需要/可以将其嵌套在引号 ( ) 中,这使得指定包含引号的文件名/文件路径变得困难。- 例如,FAT16 等文件系统不允许文件名/目录路径中出现空格,而 NTFS 或 Ext3/Ext4 等文件系统则允许。
- 例如,用于基于 Web2C 的 TeX 实现的路径搜索的 Kapathsea 库将包含字符串的文件名或文件路径
$&
视为尝试使用 shell 变量——这使得指定包含字符串的文件名变得困难$&
。 - 例如,通常
/
或\
通过使用操作系统/shell,在路径规范中将文件夹名称/目录名称彼此分开。 - 例如,在 Windows 中
:
,路径规范的某些地方并不作为文件夹/目录/文件名称的一部分,而是作为终止文件系统/数据卷/驱动器规范的内容。 - 例如在许多操作系统中
*
可以?
用作通配符。
因此,除了在文件名中使用空格字符所带来的问题之外,还有例如字符"
,$
, ,&
,/
,\
,:
,在文件名/文件路径中的使用可能会出现问题,这是由于所使用的平台/shell/操作系统所施加的限制,尽管所使用的文件系统的规范可能不限制这些字符的使用*
。?
这可能会使某些平台/shell/操作系统难以访问文件系统中的某些文件,尽管可以通过其他平台/shell/操作系统访问它们。