我需要从示例代码中给出的数据文件中读取一些值。当文件包含 # 字符时,就会出现问题。然后我收到“ ! \@xs@call 定义中的参数编号非法”错误。
关键是这些文件是由另一个程序生成的,而且文件数量很多,很难手动更改文件。
有什么想法可以解决这个问题吗?
\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}
更新
以下是示例输入文件的一部分:
# 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
.
.
.
实际上,我绘制了数据,并且我想将诸如平均值和标准差之类的附加信息放在头文件中给出的图上。
答案1
如果你只希望文件myfile2.txt可读,解决方案可能如下:
\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}
答案2
用于从您展示的典型文件中提取元数据的通用宏集。
\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}
稍微不同的方法是使用正则表达式替换。
\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}
假设元数据仅被找到一次(使用这些宏,如果出现多次,则第一次出现的结果将获胜)。如果数据缺失,\plotmean
依此类推,将扩展为“未找到”。
读取的每个文件都会覆盖宏的值。
(对于 TeX Live 2017 之前的版本,您还需要\usepackage{l3tl-analysis}
和\usepackage{l3regex}
才能\usepackage{xparse}
使用此功能。)
答案3
我使用了@Przemysław Scherwentke 给出的答案。但是,我对其进行了少许修改,以避免\catcode`#=11
每次调用时都使用\readmean
。因此,以下是我对@Przemysław 答案的改编。
\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}