查找外部文件中是否存在字符串

查找外部文件中是否存在字符串

我正在尝试寻找一种方法来确定外部 .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#4of\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}

在此处输入图片描述

相关内容