So verwenden Sie ein TeX-Makro mit einer CSV-Liste zum Filtern einer externen Datei

So verwenden Sie ein TeX-Makro mit einer CSV-Liste zum Filtern einer externen Datei

Der folgende Code erzeugt das gewünschte Ergebnis, nämlich eine Liste der Zeilen mit XXX={<value>}einem Wert <value>, der nicht in der Liste der zulässigen Werte enthalten ist:

Bildbeschreibung hier eingeben

Diese Lösung erfordert jedoch, dass ich dieselben Informationen an zwei Stellen habe, was sehr fehleranfällig ist. Gibt es also eine Möglichkeit, die Makrosequenz grep -vbasierend auf dem Inhalt von zu generieren \ListOfAcceptableValues?

Eine kompromisslose Lösung, die mir einfällt, ist die Verwendung mehrerer Dateien für jedes Element in der Liste der zulässigen Werte, aber ich denke, dass es dafür wahrscheinlich einen eleganteren Weg gibt.

Anmerkungen:

  • Ich brauche es nur, damit es unter MacOS funktioniert, daher sind alle Unix-Dienstprogramme verfügbar.
  • Ich verwende es cathier, da es die tatsächliche Verwendung dieses Makros besser emuliert.

Code:

\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}

Antwort1

\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
}

Antwort2

Eine reine LaTeX (3)-Lösung; die anfänglichen Leerzeichen bleiben allerdings nicht erhalten.

\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}

Bildbeschreibung hier eingeben


Eine andere Lösung, die reguläre Ausdrücke verwendet; ich habe es \XXXals Präfix hinzugefügt, wie Sie im Kommentar gefordert haben.

\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}

verwandte Informationen