如何使用带有 CSV 列表的 TeX 宏来过滤外部文件

如何使用带有 CSV 列表的 TeX 宏来过滤外部文件

XXX={<value>}下面的代码产生了我想要的结果,即带有的行列表,<value>该行不是允许的值列表之一:

在此处输入图片描述

但是,此解决方案要求我在两个地方拥有相同的信息,这很容易出错。那么,有没有办法grep -v根据 的内容生成宏的序列\ListOfAcceptableValues

我能想到的一个强力解决方案是对允许值列表中的每个元素使用多个文件,但我认为可能有更优雅的方法来做到这一点。

笔记:

  • 我只需要它在 MacOS 上运行,因此所有 Unix 实用程序均可用。
  • 在这里使用它cat,因为它更好地模拟了这个宏的实际用法。

代码:

\documentclass{article}
\usepackage{datatool}

%\usepackage{filecontents}% Commented out to prevent overwriting FileA.tex
\begin{filecontents*}{FileA.tex}
    XXX={AA}
some other tex content
    XXX={YY}
    XXX={BB}
and some more tex content
    XXX={ZZ}
    XXX={CC}
\end{filecontents*}

\begin{document}

\newcommand*{\ListOfAcceptableValues}{AA,BB,CC}%

%% How do I rewrite this to make use of \ListOfAcceptableValues
\immediate\write18{%
      cat FileA.tex
    | grep "XXX="
    | grep -v AA
    | grep -v BB
    | grep -v CC
    > FileB.tex
}

\DTLloadrawdb[noheader,keys={Problem}]{MyDB}{FileB.tex}%
\DTLdisplaydb{MyDB}
\end{document}

答案1

\def\foo#1,#2{| grep -v #1 \ifx\relax#2\else\expandafter\foo\expandafter#2\fi}
%% How do I rewrite this to make use of \ListOfAcceptableValues
\immediate\write18{%
      cat FileA.tex
    | grep "XXX="
    \expandafter\foo\ListOfAcceptableValues,\relax
    > FileB.tex
}

答案2

纯 LaTeX (3) 解决方案;但是,初始空间未被保留。

\begin{filecontents*}{FileA.tex}
    XXX={AA}
some other tex content
    XXX={YY}
    XXX={BB}
and some more tex content
    XXX={ZZ}
    XXX={CC}
\end{filecontents*}

\documentclass{article}
\usepackage{datatool,xparse}

\ExplSyntaxOn
\seq_new:N \g_grill_acceptable_seq
\seq_new:N \l__grill_temp_seq
\ior_new:N \l_grill_input_stream
\iow_new:N \l_grill_output_stream

\NewDocumentCommand{\SetAcceptableValues}{m}
 {
  \seq_gset_split:Nnn \g_grill_acceptable_seq { , } { #1 }
 }

\NewDocumentCommand{\ExamineFile}{mm}
 {% #1 = input file, #2 = output file
  \grill_examine_file:nn { #1 } { #2 }
 }

\cs_new_protected:Npn \grill_examine_file:nn #1 #2
 {
  \ior_open:Nn \l_grill_input_stream { #1 }
  \iow_open:Nn \l_grill_output_stream { #2 }
  \ior_open:Nn \l_grill_input_stream { #1 }
  \iow_open:Nn \l_grill_output_stream { #2 }
  \ior_map_inline:Nn \l_grill_input_stream
   { \__grill_lookup_line:n { ##1 } }
  \iow_close:N \l_grill_output_stream
  \ior_close:N \l_grill_input_stream
 }
\cs_new_protected:Npn \__grill_lookup_line:n #1
 {
  \seq_set_split:Nnn \l__grill_temp_seq { = } { #1 }
  \int_compare:nT { \seq_count:N \l__grill_temp_seq = 2 }
   {
    \tl_if_eq:nxT { XXX } { \seq_item:Nn \l__grill_temp_seq { 1 } }
     {
      \seq_if_in:NxF \g_grill_acceptable_seq
       { \seq_item:Nn \l__grill_temp_seq { 2 } }
       {
        \iow_now:Nx \l_grill_output_stream { #1 }
       }
     }
   }
 }
\cs_generate_variant:Nn \tl_if_eq:nnT {nx}
\ExplSyntaxOff

\begin{document}

\SetAcceptableValues{AA,BB,CC}
\ExamineFile{FileA}{FileB}

\DTLloadrawdb[noheader,keys={Problem}]{MyDB}{FileB.tex}%
\DTLdisplaydb{MyDB}
\end{document}

在此处输入图片描述


另一种使用正则表达式的解决方案;我已经添加\XXX为前缀,就像您在评论中要求的那样。

\begin{filecontents*}{FileA.tex}
    \XXX={AA}
some other tex content
    \XXX={YY}
    \XXX={BB}
and some more tex content
    \XXX={ZZ}
    \XXX={CC}
\end{filecontents*}

\documentclass{article}
\usepackage{datatool,xparse,l3regex}

\newcommand{\XXX}{XXX} % just to print the database

\ExplSyntaxOn
\regex_new:N \g_grill_prefix_regex

%% Here you set the prefix
%% We specify \XXX, any number of spaces and =
\regex_gset:Nn \g_grill_prefix_regex { \c{XXX} \s*? = }
%%
\regex_new:N \l__grill_acceptable_regex
\seq_new:N \g_grill_acceptable_seq
\seq_new:N \l__grill_temp_seq
\ior_new:N \l_grill_input_stream
\iow_new:N \l_grill_output_stream

\NewDocumentCommand{\SetAcceptableValues}{m}
 {
  \seq_gset_split:Nnn \g_grill_acceptable_seq { , } { #1 }
 }

\NewDocumentCommand{\ExamineFile}{mm}
 {% #1 = input file, #2 = output file
  \grill_examine_file:nn { #1 } { #2 }
 }

\cs_new_protected:Npn \grill_examine_file:nn #1 #2
 {
  \ior_open:Nn \l_grill_input_stream { #1 }
  \iow_open:Nn \l_grill_output_stream { #2 }
  \ior_open:Nn \l_grill_input_stream { #1 }
  \iow_open:Nn \l_grill_output_stream { #2 }
  \regex_set:Nx \l__grill_acceptable_regex
   {
    \exp_not:n{\cB.}
    (\seq_use:Nnnn \g_grill_acceptable_seq { | } { | } { | } )
    \exp_not:n{\cE.}
   }
  \ior_map_inline:Nn \l_grill_input_stream
   { \__grill_lookup_line:n { ##1 } }
  \iow_close:N \l_grill_output_stream
  \ior_close:N \l_grill_input_stream
 }

\cs_new_protected:Npn \__grill_lookup_line:n #1
 {
  %% Check if the prefix is present
  \regex_match:NnT \g_grill_prefix_regex { #1 }
   {
    %% Check whether the value is not among the acceptable ones
    \regex_match:NnF \l__grill_acceptable_regex { #1 }
     { \iow_now:Nn \l_grill_output_stream { #1 } }
   }
 }
\cs_generate_variant:Nn \regex_set:Nn { Nx }
\ExplSyntaxOff

\begin{document}

\SetAcceptableValues{AA,BB,CC}
\ExamineFile{FileA}{FileB}

\DTLloadrawdb[noheader,keys={Problem}]{MyDB}{FileB.tex}%
\DTLdisplaydb{MyDB}
\end{document}

相关内容