나는 사람에 대한 몇 가지 기본 정보를 파일에 저장하고 싶고 LaTeX가 이 정보를 처리할 수 있기를 원합니다. 보다 구체적으로 다음과 같은 것을 저장하고 싶습니다.
id:john1; fname: John; lname: Doe; mail: [email protected]
id:harry1; fname: Harry; lname: Potter; mail: [email protected]
등. LaTeX에서 이것이 가능합니까? 즉, 1) 이 목록을 만들고 2) \data{john1}{fname}과 같은 방법으로 이 정보를 문서에 배치하는 방법이 있습니까?
답변1
기본적 으로 파일을 읽을 수 있습니다 \read
. 데이터는 제어 시퀀스에 저장됩니다 \base:id:name
. 매크로 \data
는 단순히 이 제어 순서를 확장합니다.
\newread\basein
\def\readbase #1 {\bgroup \endlinechar=-1 \openin\basein=#1 \readbaseA}
\def\readbaseA{\ifeof\basein \egroup \else
\read\basein to\tmp
\ifx\tmp\empty \else \expandafter\base\tmp; :.; \fi
\expandafter\readbaseA \fi
}
\def\base id:#1; {\def\baseid{#1}\baseA}
\def\baseA #1:#2#3; {\ifx\end#1\end\else
\expandafter\gdef\csname base:\baseid:#1\endcsname{#2#3}%
\expandafter\baseA\fi
}
\def\data#1#2{\csname base:#1:#2\endcsname}
\readbase base.txt % reading the file
\data{john1}{fname}
답변2
자체 포함 구현:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\storedata}{mm}
{% pass control to an inner function
\konewka_store_data:nn { #1 } { #2 }
}
\DeclareExpandableDocumentCommand{\getdata}{mm}
{% just retrieve the property from the appropriate property list
\prop_item:cn { g_konewka_data_#1_prop } { #2 }
}
\seq_new:N \l__konewka_data_temp_seq
\seq_new:N \l__konewka_field_temp_seq
\cs_new_protected:Nn \konewka_store_data:nn
{
% create a property list for an ID
\prop_new:c { g_konewka_data_#1_prop }
% split the second argument
\seq_set_split:Nnn \l__konewka_data_temp_seq { ; } { #2 }
% process each field
\seq_map_inline:Nn \l__konewka_data_temp_seq
{
\__konewka_process_field:nn { #1 } { ##1 }
}
}
% we need a colon with the appropriate category code
\group_begin:
\char_set_lccode:nn { `? } { `: }
\tl_to_lowercase:n
{
\group_end:
\tl_const:Nn \c_konewka_colon_tl { ? }
}
% split the field at the colon and store the property
\cs_new_protected:Nn \__konewka_process_field:nn
{
\seq_set_split:NVn \l__konewka_data_field_seq \c_konewka_colon_tl { #2 }
\prop_gput:cxx { g_konewka_data_#1_prop }
{ \seq_item:Nn \l__konewka_data_field_seq { 1 } }
{ \seq_item:Nn \l__konewka_data_field_seq { 2 } }
}
\cs_generate_variant:Nn \seq_set_split:Nnn { NV }
\cs_generate_variant:Nn \prop_gput:Nnn { cxx }
\ExplSyntaxOff
\storedata{john1}{fname: John; lname: Doe; mail: [email protected]}
\storedata{harry1}{fname: Harry; lname: Potter; mail: [email protected]}
\begin{document}
\begin{tabular}{cccc}
Id & fname & lname & mail \\
\hline
\texttt{john1} & \getdata{john1}{fname} & \getdata{john1}{lname} & \getdata{john1}{mail} \\
\texttt{harry1} & \getdata{harry1}{fname} & \getdata{harry1}{lname} & \getdata{harry1}{mail} \\
\end{tabular}
\end{document}
파일에서 데이터를 읽을 수도 있는 버전입니다. 여기서 파일은 으로 추가되지만 filecontents
형식이 표시된 대로라면 무엇이든 가능합니다. 콜론과 세미콜론 주위의 공백은 무시됩니다.
\begin{filecontents*}{\jobname.csv}
id:john1; fname: John; lname: Doe; mail: [email protected]
id:harry1; fname: Harry; lname: Potter; mail: [email protected]
\end{filecontents*}
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\storedata}{mm}
{% pass control to an inner function
\konewka_add_id:n { #1 }
\konewka_store_data:nn { #1 } { #2 }
}
\NewDocumentCommand{\readdata}{m}
{
\konewka_read_data:n { #1 }
}
\DeclareExpandableDocumentCommand{\getdata}{mm}
{% just retrieve the property from the appropriate property list
\prop_item:cn { g_konewka_data_#1_prop } { #2 }
}
\NewDocumentCommand{\listIDs}{}
{% just an example
\seq_use:Nn \g_konewka_id_seq { ,~ }
}
%%% variables
% we need a colon with the appropriate category code
\tl_const:Nx \c_konewka_colon_tl { \tl_to_str:n {:} }
% other variables
\seq_new:N \g_konewka_id_seq
\tl_new:N \l__konewka_id_tl
\seq_new:N \l__konewka_data_temp_seq
\seq_new:N \l__konewka_field_temp_seq
\ior_new:N \g__konewka_read_data_stream
%%% variants of kernel functions
\cs_generate_variant:Nn \seq_set_split:Nnn { NV , NVV }
\cs_generate_variant:Nn \prop_gput:Nnn { cxx }
%%% our functions
% add the new id to a sequence for possible later usage
\cs_new_protected:Nn \konewka_add_id:n
{
\seq_gput_right:Nn \g_konewka_id_seq { #1 }
}
\cs_generate_variant:Nn \konewka_add_id:n { V }
% the inner function for \storedata
\cs_new_protected:Nn \konewka_store_data:nn
{
% create a property list for an ID
\prop_new:c { g_konewka_data_#1_prop }
% split the second argument at semicolons
\seq_set_split:Nnn \l__konewka_data_temp_seq { ; } { #2 }
% populate the property list
\__konewka_process_entry:n { #1 }
}
% the inner function for \readdata
\cs_new_protected:Nn \konewka_read_data:n
{
\ior_open:Nn \g__konewka_read_data_stream { #1 }
\ior_map_inline:Nn \g__konewka_read_data_stream
{
% split a line into fields
\seq_set_split:Nnn \l__konewka_data_temp_seq { ; } { ##1 }
% retrieve the first field (ID)
\seq_pop_left:NN \l__konewka_data_temp_seq \l__konewka_id_tl
% split at colon and set the ID to the second part
\seq_set_split:NVV \l__konewka_data_field_seq \c_konewka_colon_tl \l__konewka_id_tl
\tl_set:Nx \l__konewka_id_tl { \seq_item:Nn \l__konewka_data_field_seq { 2 } }
% add the id to the list
\konewka_add_id:V \l__konewka_id_tl
% populate the property list
\__konewka_process_entry:V \l__konewka_id_tl
}
}
% auxiliary function
\cs_new_protected:Nn \__konewka_process_entry:n
{
\seq_map_inline:Nn \l__konewka_data_temp_seq
{
\seq_set_split:NVn \l__konewka_data_field_seq \c_konewka_colon_tl { ##1 }
\prop_gput:cxx { g_konewka_data_#1_prop }
{ \seq_item:Nn \l__konewka_data_field_seq { 1 } }
{ \seq_item:Nn \l__konewka_data_field_seq { 2 } }
}
}
\cs_generate_variant:Nn \__konewka_process_entry:n { V }
\ExplSyntaxOff
\readdata{\jobname.csv}
\storedata{uthor1}{fname: Algernon; lname: Uthor; mail: [email protected]}
\storedata{riter1}{fname: Walter; lname: Riter; mail: [email protected]}
\begin{document}
\begin{tabular}{cccc}
Id & fname & lname & mail \\
\hline
\texttt{john1} & \getdata{john1}{fname} & \getdata{john1}{lname} & \getdata{john1}{mail} \\
\texttt{harry1} & \getdata{harry1}{fname} & \getdata{harry1}{lname} & \getdata{harry1}{mail} \\
\texttt{uthor1} & \getdata{uthor1}{fname} & \getdata{uthor1}{lname} & \getdata{uthor1}{mail} \\
\texttt{riter1} & \getdata{riter1}{fname} & \getdata{riter1}{lname} & \getdata{riter1}{mail} \\
\end{tabular}
\medskip
The IDs are: \listIDs
\end{document}