12

I need to read some values from data files as given in the sample code. The problem arises when the files contain # character. Then I get " ! Illegal parameter number in definition of \@xs@call " error.

The point is the files are generated by another program and there are bunch of them that makes it difficult to simply change the files by hand.

Any ideas how to deal this issue?

\documentclass{article}
\usepackage{xstring}
\usepackage{filecontents}

% WORKS FINE !!!
\begin{filecontents*}{myfile1.txt}
mean: 0.26068087303584447 lablab
\end{filecontents*}

% if in my file there are special characters (e.g #) then I get errors :( !!!
\begin{filecontents*}{myfile2.txt}
# mean: 0.26068087303584447 lablab
\end{filecontents*}

\newread\myread  
\newcommand{\readmean}[1]{
  \openin\myread=#1
  \read\myread to \mystr
  \StrBetween{\mystr}{mean: }{ lablab}[\mymean]
  \closein\myread
}

\begin{document}

\readmean{myfile1.txt}
mean1 : \mymean

\readmean{myfile2.txt}
mean2 : \mymean

\end{document}

UPDATE

Here is part of an example input file:

 # created by PartHist. 
 # range: 0.0 - 1.0
 # mPDF info : 
 # mean: 0.10367941480330108 std:0.081293127812218507
 # args: (1.3542643666732745, 11.707772771967631)
 #
 x y
 0.02 6.47
 0.04 3.21
 .
 .
 .

Actually I plot the data and I would like to put the additional information like mean and std on the plot which is given in the header file.

  • Do all lines start with #? Is the final string variable or fixed? Is the start always # mean:? – egreg Nov 3 '13 at 13:25
  • Can you show a short example of a typical file? – egreg Nov 3 '13 at 15:23
  • @egreg now I updated the question and added part of a typical file. – A.GH Nov 3 '13 at 15:42
  • Now it's less clear; do you want to read only the mean line? – egreg Nov 3 '13 at 16:23
  • @egreg I'd like to read mean, std as well as values given in front of args. and finally on my plot I'd like to add the information like: mean=0.10367941480330108, std=0.081293127812218507, alpha=1.3542643666732745 and beta=11.707772771967631. – A.GH Nov 3 '13 at 16:35
7

If you want only the file myfile2.txt to be readable, the solution may be as follows:

\documentclass{article}
\usepackage{xstring}
\usepackage{filecontents}

% WORKS FINE !!!
\begin{filecontents*}{myfile1.txt}
mean: 0.26068087303584447 lablab
\end{filecontents*}

% if in my file there are special characters (e.g #) then I get errors :( !!!
\begin{filecontents*}{myfile2.txt}
# mean: 0.26068087303584447 lablab
\end{filecontents*}

\newread\myread  
\newcommand{\readmean}[1]{
  \openin\myread=#1
  \read\myread to \mystr
  \StrBetween{\mystr}{mean: }{ lablab}[\mymean]
  \closein\myread
}

\begin{document}

\readmean{myfile1.txt}
mean1 : \mymean

{\catcode`\#=11
\readmean{myfile2.txt}
mean2 : \mymean
}


\end{document}

enter image description here

6

A general macro set for extracting the metadata from the typical file you showed.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\getmetadata}{m}
 {
  \agh_getmetadata:n { #1 }
 }

\ior_new:N \g_agh_input_ior
\tl_const:Nx \c_agh_hashmark_tl { \token_to_str:N # }

\cs_generate_variant:Nn \tl_if_in:nnTF { nV }
\cs_generate_variant:Nn \tl_replace_once:Nnn { Nx }

\cs_new_protected:Npn \agh_getmetadata:n #1
 {
  \ior_open:Nn \g_agh_input_ior { #1 }
  \ior_str_map_inline:Nn \g_agh_input_ior
   { % read only lines containing #
    \tl_if_in:nVTF { ##1 } \c_agh_hashmark_tl
     {
      \agh_readline:n { ##1 }
     }
     {
      \ior_map_break:
     }
   }
 }

\cs_new_protected:Npn \agh_readline:n #1
 { % add a trailing space
  \tl_set:Nn \l_agh_current_line_tl { #1 }
  \tl_put_right:Nn \l_agh_current_line_tl { ~ }
  % change `mean:' into \agh_mean:w
  \tl_replace_once:Nxn \l_agh_current_line_tl
   { \tl_to_str:n { mean: } }
   { \agh_mean:w }
  % change `std:' into \agh_std:w
  \tl_replace_once:Nxn \l_agh_current_line_tl
   { \tl_to_str:n { std: } }
   { \agh_std:w }
  % change `args:' into \agh_args:w
  \tl_replace_once:Nxn \l_agh_current_line_tl
   { \tl_to_str:n { args: } }
   { \agh_args:w }
  % deliver the token list in a box
  % so the macros will do their work
  % and the other characters will be ignored
  \hbox_set:Nn \l_tmpa_box { \l_agh_current_line_tl }
 }

\cs_new:Npn \agh_mean:w #1#2 ~ %
 {
  \cs_gset:Npn \plotmean { #1#2 }
 }

\cs_new:Npn \agh_std:w #1#2 ~ %
 {
  \cs_gset:Npn \plotstd { #1#2 }
 }

\cs_new:Npn \agh_args:w #1(#2,#3#4) ~ %
 {
  \cs_gset:Npn \plotalpha { #2 }
  \cs_gset:Npn \plotbeta  { #3#4 }
 }

\ExplSyntaxOff

\begin{document}

\getmetadata{agh.txt}

\noindent
Mean is \plotmean\\
Std is \plotstd\\
Alpha is \plotalpha\\
Beta is \plotbeta

\end{document}

enter image description here

A slightly different approach uses regular expression substitution.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\getmetadata}{m}
 {
  \agh_getmetadata:n { #1 }
 }

\ior_new:N \g_agh_input_ior
\tl_const:Nx \c_agh_hashmark_tl { \token_to_str:N # }
\tl_new:N \l_agh_metadata_tl
\tl_new:N \l_agh_temp_tl
\seq_new:N \l_agh_args_seq

\cs_generate_variant:Nn \tl_if_in:nnT { nV }
\cs_generate_variant:Nn \tl_replace_once:Nnn { Nx }

\cs_new_protected:Npn \agh_getmetadata:n #1
 {
  \tl_clear:N \l_agh_metadata_tl
  \ior_open:Nn \g_agh_input_ior { #1 }
  \ior_str_map_inline:Nn \g_agh_input_ior
   { % read only lines containing #
    \tl_if_in:nVT { ##1 } \c_agh_hashmark_tl
     {
      \tl_put_right:Nn \l_agh_metadata_tl { ##1 }
     }
   }
  \agh_search_mean:
  \agh_search_std:
  \agh_search_args:
 }

\cs_new_protected:Npn \agh_search_mean:
 {
  \tl_gset:Nn \plotmean { Not~found }
  \tl_set_eq:NN \l_agh_temp_tl \l_agh_metadata_tl
  \regex_replace_once:nnNT
   {\A .*? mean\: \s*? ( (\+|\-)? [0-9]* \.? [0-9]+ ) .* \Z } 
   { \1 }
   \l_agh_temp_tl
   { \tl_gset_eq:NN \plotmean \l_agh_temp_tl }
 }

\cs_new_protected:Npn \agh_search_std:
 {
  \tl_gset:Nn \plotstd { Not~found }
  \tl_set_eq:NN \l_agh_temp_tl \l_agh_metadata_tl
  \regex_replace_once:nnNT
   {\A .*? std\: \s*? ( (\+|\-)? [0-9]* \.? [0-9]+ ) .* \Z } 
   { \1 }
   \l_agh_temp_tl
   { \tl_gset_eq:NN \plotstd \l_agh_temp_tl }
 }

\cs_new_protected:Npn \agh_search_args:
 {
  \tl_gset:Nn \plotargs  { Not~found }
  \tl_gset:Nn \plotalpha { Not~found }
  \tl_gset:Nn \plotbeta  { Not~found }
  \tl_set_eq:NN \l_agh_temp_tl \l_agh_metadata_tl
  \regex_replace_once:nnNT
   {\A .*? args\: \s*? \( ( [^\)]* ) \) .* \Z }
   { \1 }
   \l_agh_temp_tl
   { \tl_gset:Nx \plotargs { (\l_agh_temp_tl) } \agh_split_args: }
 }

\cs_new_protected:Npn \agh_split_args:
 {
  \seq_set_split:NnV \l_agh_args_seq { , } \l_agh_temp_tl
  \tl_set:Nx \plotalpha { \seq_item:Nn \l_agh_args_seq { 1 } }
  \tl_set:Nx \plotbeta  { \seq_item:Nn \l_agh_args_seq { 2 } }
 }
\ExplSyntaxOff

\begin{document}

\getmetadata{agh.txt}

\noindent
Mean is \plotmean\\
Std is \plotstd\\
Args is \plotargs\\
Alpha is \plotalpha\\
Beta is \plotbeta

\end{document}

It is assumed that the metadata are found only once (the first appearance wins, with these macros, in case of multiple appearance). If data are missing, \plotmean and so on will expand to “Not found”.

Every file read will overwrite the macros' values.

(For releases before TeX Live 2017, you will need \usepackage{l3tl-analysis} and \usepackage{l3regex} in addition to \usepackage{xparse} for this to work.)

2

I used the answer given by @Przemysław Scherwentke. However, I changed it a little bit in order to avoid using \catcode`#=11 every time I call \readmean . Therefore, the following is my adaptation of @Przemysław's answer.

\documentclass{article}
\usepackage{xstring}
\usepackage{filecontents}

\begin{filecontents*}{myfile1.txt}
mean: 0.26068087303584447 lablab
\end{filecontents*}

\begin{filecontents*}{myfile2.txt}
# mean: 0.26068087303584447 lablab
\end{filecontents*}

\newread\myread  
\newcommand{\readmean}[1]{
  \openin\myread=#1
  {\catcode`\#=11
  \read\myread to \mystr
  \StrBetween{\mystr}{mean: }{ lablab}[\mystr]
  \global\edef\mymean{\mystr}
  }
  \closein\myread
}

\begin{document}

\readmean{myfile1.txt}
mean1 : \mymean

\readmean{myfile2.txt}
mean2 : \mymean

\end{document}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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