我正在尝试寻找一种方法来确定外部 .tex 文件中是否存在特定文本或字符串。这就像接受用户的文本输入并确定是否可以在您的 .tex 文件中找到该文本。例如,如果文章标题存在于您的 .tex 或 .bib 文件中,您可能想要搜索该文章的标题。考虑以下 MWE。
%MWE
\documentclass{article}
%this is a temporary definition, just to declare the command.
\newcommand*{\mySearchforStringinExternalFilesCommand}[4]{#1#2#3#4}
%first argument is the text/string to be searched.
%second argument is a list of external files that will be searched if the given string is present.
%third argument is the output if the string is found.
%fourth argument is the output if the stsring is not found.
\begin{document}
%I am trying to search for the text ``vibration'' if it is present inside the external files datafileone.tex, datafiletwo.tex, and datafilethree.tex.
%If the text can be found inside the external files, then ``The search phrase ... was found in ... '' will be printed in the pdf file together with the filename/s of the external file/s where the text was found. If not, then ``The search phrase was not found in any of the datafiles.'' will be printed.
%datafileone.tex contains the phrase ``amplitude of vibration''.
%datafiletwo.tex contains the phrase ``frequency of vibration''.
%datafilethree.tex contains the phrase ``instantaneous frequency and instantaneous amplitude''. (these are terms from my thesis :) )
%Therefore, if the macro \mySearchforStringinExternalFilesCommand is designed properly, it must output ``The search phrase `vibration' was found in datafileone.tex and datafiletwo.tex''
\mySearchforStringinExternalFilesCommand%
{vibration}%This is the text or string to be searched in the given external files.
{%These are the external files.
datafileone.tex%
datafiletwo.tex%
datafilethree.tex%
}%
{The search phrase ... was found in ...}%datafileone.tex and/or datafiletwo.tex and/or datafilethree.tex
{The search phrase was not found in any of the datafiles.}%This is printed if the text is not found.
\end{document}
\replacelineonce{<file>}{<search string>}{<replacement>}{<true code>}{<false code>}
Phelype Oleinik 使用 expl3 语法并提出了查找和替换的命令,可以在如何替换 TeX' \write 命令写入的文件中一行。代码如下(取自URL)
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand \replacelineonce { m m m m m }
{ \mountain_replace_once:nnnTF {#1} {#2} {#3} {#4} {#5} }
\NewDocumentCommand \replacelineall { m m m m m }
{ \mountain_replace_all:nnnTF {#1} {#2} {#3} {#4} {#5} }
\tl_new:N \l__mountain_tmpa_tl
\tl_new:N \l__mountain_file_seq
\bool_new:N \l__mountain_replaced_bool
\ior_new:N \l__mountain_replace_ior
\iow_new:N \l__mountain_replace_iow
\prg_new_protected_conditional:Npnn \mountain_replace_once:nnn #1 #2 #3 { T, F, TF }
{ \__mountain_replace_aux:Nnnn \c_false_bool {#1} {#2} {#3} }
\prg_new_protected_conditional:Npnn \mountain_replace_all:nnn #1 #2 #3 { T, F, TF }
{ \__mountain_replace_aux:Nnnn \c_true_bool {#1} {#2} {#3} }
\cs_new_protected:Npn \__mountain_replace_aux:Nnnn #1 #2 #3 #4
{
\ior_open:NnTF \l__mountain_replace_ior {#2}
{ \__mountain_replace_line:Nnnn #1 {#3} {#4} {#2} }
{
\msg_error:nnn { mountain } { file-not-found } {#2}
\prg_return_false:
}
}
\cs_new_protected:Npn \__mountain_replace_line:Nnnn #1 #2 #3 #4
{
\seq_clear:N \l__mountain_file_seq
\bool_set_false:N \l__mountain_replaced_bool
\ior_str_map_inline:Nn \l__mountain_replace_ior
{
\str_if_eq:nnTF {##1} {#2}
{
\bool_set_true:N \l__mountain_replaced_bool
\seq_put_right:Nn \l__mountain_file_seq {#3}
\bool_if:NF #1
{ \ior_map_break:n { \__mountain_replace_skip: } }
}
{ \seq_put_right:Nn \l__mountain_file_seq {##1} }
}
\__mountain_replace_end:n {#4}
}
\cs_new_protected:Npn \__mountain_replace_skip:
{
\ior_str_map_inline:Nn \l__mountain_replace_ior
{ \seq_put_right:Nn \l__mountain_file_seq {##1} }
}
\cs_new_protected:Npn \__mountain_replace_end:n #1
{
\ior_close:N \l__mountain_replace_ior
\iow_open:Nn \l__mountain_replace_iow {#1}
\seq_map_inline:Nn \l__mountain_file_seq
{ \iow_now:Nn \l__mountain_replace_iow {##1} }
\iow_close:N \l__mountain_replace_iow
\bool_if:NTF \l__mountain_replaced_bool
{ \prg_return_true: }
{ \prg_return_false: }
}
\msg_new:nnn { mountain } { file-not-found }
{ File~`#1'~not~found. }
\ExplSyntaxOff
\begin{document}
\newwrite\tempfile
\immediate\openout\tempfile=lists.tex
\immediate\write\tempfile{line1}
\immediate\write\tempfile{}
\immediate\write\tempfile{line2}
\immediate\write\tempfile{}
\immediate\write\tempfile{line2}
\immediate\write\tempfile{}
\immediate\write\tempfile{line2}
\immediate\closeout\tempfile
\replacelineonce{lists.tex}{line2}{line replaced}
{Replaced once:}
{Nothing replaced:}
\input{lists}
\bigskip
\replacelineall{lists.tex}{line2}{line replaced}
{Replaced all:}
{Nothing replaced:}
\input{lists}
\bigskip
\replacelineonce{lists.tex}{line2}{line replaced}
{Replaced once:}
{Nothing replaced:}
\input{lists}
\bigskip
\end{document}
不过,我的兴趣只是“寻找”,而不是“寻找并替换”。
另一个类似的主题是使用 \include 在包含许多“包含”文件的文档中查找和替换
请寻求您的帮助。
答案1
已编辑以克服某些 catcode 的输入字符限制。请注意datafileone.tex
,在 中,单词vibration
是参数定义的一部分。在 中datafiletwo.tex
,单词vibration
是注释的一部分,除非您在宏定义中注释掉特定行,否则也会对其进行搜索。添加该文件datafilefour.tex
是为了提供无法找到搜索词的情况。
警告:在当前版本的软件包中readarray
(将在未来的更新中修复),行尾始终在 期间被丢弃\readdef
并替换为 的值\readarraysepchar
,这不是读取行尾的自然 LaTeX 方式。这可能会影响搜索字符串跨越多行输入的搜索。
参数#3
和#4
of\mySearchforStringinExternalFilesCommand
本身预计分别接受 2 个和 1 个参数,无论它们是否对这些参数执行任何操作。在 的情况下,#3
传递的两个参数包括搜索字符串和找到匹配项的文件名。在 的情况下#4
,传递的参数是搜索字符串。
编辑以演示或者搜索,可以同时指定多个搜索字符串,使用listofitems
或者比较器||
,如vibration||frequency
。
\begin{filecontents*}[overwrite]{datafileone.tex}
\today \def\mashit#1{\textit{amplitude #1 of vibration}}
\end{filecontents*}
\begin{filecontents*}[overwrite]{datafiletwo.tex}
frequency of something% REMEMBER TO CALL IT vibration
\end{filecontents*}
\begin{filecontents*}[overwrite]{datafilethree.tex}
instantaneous frequency and instantaneous amplitude
\end{filecontents*}
\begin{filecontents*}[overwrite]{datafilefour.tex}
none of the above
\end{filecontents*}
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{readarray,listofitems}
\readarraysepchar{ }% CURRENT readarray VERSION WILL INSERT THIS
% AUTOMATICALLY AFTER EACH INPUT RECORD IS READ (EVEN IF RECORD ENDS
% ON A MACRO OR `%')
\def\killcats{%
\catcode`\#=12
\catcode`\%=12 % COMMENT TO AVOID SEARCH OF COMMENTS
\catcode`\\=12
\catcode`\{=12
\catcode`\}=12 }
\def\restorecats{%
\catcode`\\=0
\catcode`\}=2
\catcode`\{=1
\catcode`\%=14
\catcode`\#=6 }%
\newcommand*{\mySearchforStringinExternalFilesCommand}[4]{%
\def\findstatus{F}%
\setsepchar{,}%
\readlist*\filelist{#2}%
\setsepchar{#1}%
\foreachitem\z\in\filelist[]{%
\killcats
\expandafter\readdef\expandafter{\z}\tmpfile
\restorecats
\readlist\searchlist{\tmpfile}%
\ifnum\searchlistlen>1\relax#3{#1}{\z}\def\findstatus{T}\fi
}
\if F\findstatus #4{#1}\fi
}
\newcommand\searchtrue[2]{The search phrase ``#1'' was found in #2.\par}
\newcommand\searchfalse[1]{The search phrase ``#1'' was not found in
any of the datafiles.\par}
\begin{document}
\mySearchforStringinExternalFilesCommand%
{vibration}
{datafileone.tex, datafiletwo.tex, datafilethree.tex, datafilefour.tex}
{\searchtrue}{\searchfalse}
\bigskip
\mySearchforStringinExternalFilesCommand%
{frequency}
{datafileone.tex, datafiletwo.tex, datafilethree.tex, datafilefour.tex}
{\searchtrue}{\searchfalse}
\bigskip
\mySearchforStringinExternalFilesCommand%
{vibration||frequency}
{datafileone.tex, datafiletwo.tex, datafilethree.tex, datafilefour.tex}
{\searchtrue}{\searchfalse}
\end{document}
答案2
您可以将文件存储在标记列表变量中并进行检查。
的第三个参数\lookfortextinfiles
是一个模板,其中#1
代表匹配的文件名。第四个参数是可选的,表示在没有匹配的情况下要做什么。我假设您想执行类似\input{#1}
或\bibliography{#1}
如果文件是.bib
文件的操作,而不仅仅是打印匹配的文件名列表。
\begin{filecontents*}{\jobname-one.tex}
amplitude of vibration
\end{filecontents*}
\begin{filecontents*}{\jobname-two.tex}
frequency of vibration
\end{filecontents*}
\begin{filecontents*}{\jobname-three.tex}
instantaneous frequency and instantaneous amplitude
\end{filecontents*}
\documentclass{article}
\ExplSyntaxOn
\NewDocumentCommand{\lookfortextinfiles}{m m +m +O{}}
{% #1 = text to look for
% #2 = list of files to look into
% #3 = template
% #4 = what to do in case of no match
\beethovengg_lookfor:nnnn { #1 } { #2 } { #3 } { #4 }
}
\tl_new:N \l__beethovengg_lookfor_file_tl
\seq_new:N \l__beethovengg_lookfor_match_seq
\cs_new_protected:Nn \beethovengg_lookfor:nnnn
{
\seq_clear:N \l__beethovengg_lookfor_match_seq
\clist_map_inline:nn { #2 }
{
\file_get:nnN { ##1 } { } \l__beethovengg_lookfor_file_tl
\tl_if_in:VnT \l__beethovengg_lookfor_file_tl { #1 }
{
\seq_put_right:Nn \l__beethovengg_lookfor_match_seq { ##1 }
}
}
\cs_set:Nn \__beethoven_lookfor_use:n { #3 }
\seq_map_function:NN \l__beethovengg_lookfor_match_seq \__beethoven_lookfor_use:n
\seq_if_empty:NT \l__beethovengg_lookfor_match_seq { #4 }
}
\ExplSyntaxOff
\begin{document}
\lookfortextinfiles{vibration}{
\jobname-one,
\jobname-two,
\jobname-three,
}{Found in #1\par}[Found in no file]
\bigskip
\lookfortextinfiles{frequency}{
\jobname-one,
\jobname-two,
\jobname-three,
}{Found in #1\par}[Found in no file]
\bigskip
\lookfortextinfiles{foo}{
\jobname-one,
\jobname-two,
\jobname-three,
}{Found in #1\par}[Found in no file]
\end{document}