0

My code/idea from 2 topics: Input a parameter from another file filecontents: select rows of group to display

File parameters.tex:

\documentclass{article}
\usepackage[utf8]{vietnam}
\usepackage{verbatim}
\usepackage{comment}
\usepackage{filecontents}
\begin{filecontents*}{products.tex}
No|Time|Velocity
11|"5s"|"3m/s"
22|"10s"|"7m/s"
33|"20s"|"14m/s"
\end{filecontents*}
\usepackage{datatool}
\DTLsetseparator{|}
\DTLloaddb[autokeys=false]{products}{products.tex}
\newcommand{\printtype}[1]{%
  \par
   \DTLforeach*
    [\DTLiseq{\No}{#1}]% Condition
    {products}% Database
    {\No=No,\Time=Time,\Velocity=Velocity}{%
    time = \Time     \par max\_velocity =  \Velocity
    }% 
}

\begin{document}
\printtype{11}
\end{document}

Compiling this parameters.tex file produces a DVI or PDF file containing:

time = 5s
max_velocity = 3m/s

But I would like to parse this output from the following main.tex file and be able to use the “time” and “max_velocity” values from within main.tex.

File main.tex:

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn

\ior_new:N \ar_param_file

\seq_new:N \g_ar_param_seq


\cs_new:Nn \ar_read_by_line:n {%
  \seq_gput_right:Nn \g_ar_param_seq {#1}% Appending the current line to the global sequence buffer
}
\NewDocumentCommand{\paraminput}{O{}m}{%
  \seq_gclear:N \g_ar_param_seq% Clearing the sequence
  \ior_open:Nn \ar_param_file {#2} % Open the input file
  \ior_map_inline:Nn \ar_param_file {\ar_read_by_line:n{##1}}% Reading line by line
  \ior_close:N \ar_param_file% Closing the line
  \seq_map_inline:Nn \g_ar_param_seq {% Traversing through the line
    \seq_set_split:Nnn \l_tmpa_seq {=} {##1} % Splitting each line into 'key=value' pairs
    \seq_if_in:NxT \l_tmpa_seq {#1} {\seq_item:Nn \l_tmpa_seq {2}\seq_map_break:}% Checking if `#1` is in the sequence and display it with \seq_item:Nn..., then break the mapping loop.
  }
}

\ExplSyntaxOff

\begin{document}
The trajectory travels the distance of 
\paraminput[time]{parameters.tex}. % <==========================
The maximum observed velocity is \paraminput[max_velocity]{parameters.tex}. ...
\end{document}

I use LaTeX, texmarker? How can I use the parameters output by parameters.tex from within main.tex? Do I need R or only LaTeX?

TeXnician
  • 33,589
latexforti
  • 2,091
  • 1
    Your main.tex reads data in text format, but the lines containing “time = 5s” and “max velocity = 3m/s” produced par your parameters.tex (or paramters.tex...) are not written to a text file, they are written do DVI or PDF, depending on how you compile parameters.tex. You could either modify parameters.tex to produce a text file (using \write or a LaTeX3 equivalent), or change your main.tex to read directly from the input file, products.tex. I don't know the parsing rules of datatool.sty (double quotes seem to be specially handled), but the second sol. seems more straightforward. – frougon Apr 12 '19 at 15:45
  • 1
    I've added an answer that minimally modifies your parameters.tex to produce the sentence at the end of your second file. Is this what you want to achieve? If not, please describe it more accurately. – frougon Apr 12 '19 at 16:34
  • @frougon can you guide me more about: "modify parameters.tex to produce a text file (using \write or a LaTeX3 equivalent)" - i want to use 2 saparated file: parameter and main.tex. thanks – latexforti Apr 13 '19 at 00:22
  • 1
    Okay, I have replaced my answer. Is this what you want? Note that I used parameters.txt for the output file name; parameters.tex is not a great name, because the file doesn't use TeX syntax. I also improved the LaTeX3 code and formatting in your main.tex, see my answer below. – frougon Apr 13 '19 at 09:21

1 Answers1

1

Apparently, you really want to write to an intermediate file in text format. Here is one way to do that, with \write (note that the output file is named parameters.txt).

Contents of parameters.tex:

\RequirePackage{filecontents}

\begin{filecontents*}{products.tex}
No|Time|Velocity
11|"5s"|"3m/s"
22|"10s"|"7m/s"
33|"20s"|"14m/s"
\end{filecontents*}

\documentclass{article}
\usepackage{datatool}
\DTLsetseparator{|}
\DTLloaddb[autokeys=false]{products}{products.tex}

\newwrite\myOutput
\immediate\openout\myOutput=parameters.txt
\AtEndDocument{\immediate\closeout\myOutput}

\newcommand{\printForNumber}[1]{%
  \DTLforeach*%
    [\DTLiseq{\No}{#1}]% Condition
    {products}% Database
    {\No=No,\Time=Time,\Velocity=Velocity}{%
      \immediate\write\myOutput{time=\Time}%
      \immediate\write\myOutput{max_velocity=\Velocity}%
    }%
  }

\begin{document}
\printForNumber{11}
\end{document}

This produces a file called parameters.txt, containing the following lines:

time=5s
max_velocity=3m/s

Your main.tex code works with that, at the condition that you replace parameters.tex with parameters.txt in the two \paraminput[〈param name〉]{〈file〉} calls. However, the way used in your main.tex code to select the first line containing the desired parameter name (here: time or max_velocity) can be improved a little bit—you'll find my proposal below. The main problem in my opinion is that your equality test for the given parameter name applies to both sides of the equal sign: the parameter name (okay) and also the parameter value (not fantastic...).

I also tried to arrange the code according to LaTeX3-recommended code style (see The LaTeX3 Pro­gram­ming Lan­guage and LaTeX3 style guide on this page). I moved the whole logic of the \paraminput command into a new \ar_find_data_in_file:nn protected command, so that the document-level command (\paraminput) just calls \ar_find_data_in_file:nn with its two arguments. The empty default value for the optional argument of \paraminput is strange, but I suppose you are going to replace it with time, max_velocity or something like that. Therefore, I didn't change this optional argument into a mandatory one. So, here is the revised main.tex file:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\ior_new:N \g_ar_param_file
\seq_new:N \g_ar_param_seq

\cs_new_protected:Nn \__ar_read_by_line:n
  {
    % Append the current line to the global sequence \g_ar_param_seq
    \seq_gput_right:Nn \g_ar_param_seq {#1}
  }

% #1: parameter name such as 'time' or 'max_velocity'
% #2: input file
\cs_new_protected:Npn \ar_find_data_in_file:nn #1#2
  {
    \seq_gclear:N \g_ar_param_seq      % Clear the sequence
    \ior_open:Nn \g_ar_param_file {#2} % Open the input file #2
    % Read it line by line into sequence \g_ar_param_seq
    \ior_map_inline:Nn \g_ar_param_file { \__ar_read_by_line:n {##1} }
    \ior_close:N \g_ar_param_file      % Close the file

    \seq_map_inline:Nn \g_ar_param_seq % For each line
      { % Split it around the '=' sign
        \seq_set_split:Nnn \l_tmpa_seq {=} {##1}
        % Get the parameter name
        \seq_get_left:NN \l_tmpa_seq \l_tmpa_tl

        % If #1 is the name of the parameter for the current line, leave it in
        % the TeX input stream and break out of the mapping loop.
        \str_if_eq:VnT \l_tmpa_tl {#1}
          {
            \seq_map_break:n % Get the parameter value and break
              { \seq_item:Nn \l_tmpa_seq { 2 } }
          }
      }
  }

\NewDocumentCommand \paraminput { O{} m }
  {
    \ar_find_data_in_file:nn {#1} {#2}
  }

\ExplSyntaxOff

\begin{document}
The trajectory took \paraminput[time]{parameters.txt}.
The maximum observed velocity was \paraminput[max_velocity]{parameters.txt}.
\end{document}

screenshot of main.pdf

frougon
  • 24,283
  • 1
  • 32
  • 55
  • thank for your help. But i want 2 file: parameter.tex và main.tex. Not merge. Thanks – latexforti Apr 13 '19 at 00:18
  • 1
    Done, please see above. – frougon Apr 13 '19 at 09:23
  • @fourgon: thank. You're my hero. I tested: when i change No = 22 but The result/file parameter.txt not change, always: time = 5s, max_velocity= 3m/s. This parameter.txt is closed. I use Texmaker 5.0.3. One other question: If any, i change no in parameter.tex but compile only one time with main.tex. Don't need compile parameters.tex then compile main.tex. Thanks – latexforti Apr 13 '19 at 11:40
  • 1
    It works here: if I change the first file (parameters.tex) to have \printForNumber{22} instead of \printForNumber{11}, recompile this parameters.tex then main.tex, I see “The trajectory took 10s. The maximum observed velocity was 7m/s.” in main.pdf. You have to recompile parameters.tex before main.tex if you want to see any change, because this is what generates parameters.txt, which is the input of main.tex. This is the disadvantage when using an intermediate file. That is why my first solution didn't use one. – frougon Apr 13 '19 at 12:12
  • thank for answer. i will try again. Your first Solution is good if main.tex is simple and there are 2-5 parameters. My real main.tex : > 2000 rows, and Parameter > 100 variables. – latexforti Apr 13 '19 at 12:17
  • 1
    Thanks, I sense another problem here: your parameter.txt does not contain the No field (11, 22, 33) and the algorithm from your main.tex, which I kept for the most part, exits as soon as it found a match (time or max_velocity parameter name). If you have several \printForNumber{...} in parameters.tex, the way things currently are, only the first one will be used by main.tex, because it doesn't do anything to find the data for a particular row: it just takes the first one. – frougon Apr 13 '19 at 12:28
  • 1
    In other words, if you want to write several rows of data to parameters.txt, it seems to me that you should change its format too, and I am not sure of the benefit as compared to my first solution... – frougon Apr 13 '19 at 12:57
  • thank so much. your both solution are awesome. i will test more each solution then i will select 1 or 2 solution. Thanks – latexforti Apr 13 '19 at 13:07