Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

The code below produces the results I desire, which is a list of the lines with XXX={<value>} with a <value> which is not one of the allowed list of values:

enter image description here

However, this solution requires me to have the same information in two places which is very error prone. So, is there a way I can generated the sequence of the grep -v macros based on the contents of \ListOfAcceptableValues.

A brute force solution I can think of is to use multiple files for each element in the list of allowed values, but am thinking that there is probably a more elegant way to do this.

Notes:

  • I only need it to work on MacOS, so all the Unix utilities are available.
  • Am using cat here as it better emulates the actual usage of this macro.

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}
share|improve this question
add comment

2 Answers 2

up vote 4 down vote accepted
\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
}
share|improve this answer
add comment

A pure LaTeX (3) solution; the initial spaces are not preserved, though.

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

enter image description here


Another solution that uses regular expressions; I've added \XXX as the prefix, like you asked in the comment.

\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}
share|improve this answer
    
+1 for rising to a challenge:-) –  David Carlisle Apr 2 '13 at 23:30
    
This works for the given MWE, but has issues for instance with \XXX={YY}. That was why I was trying to do it in the Unix shell. Not that that was mentioned in the original specification though. –  Peter Grill Apr 2 '13 at 23:40
    
@PeterGrill The regex solution can take care also of that case. –  egreg Apr 3 '13 at 0:00
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.