![conf 파일을 속성 목록으로 읽기](https://rvso.com/image/298823/conf%20%ED%8C%8C%EC%9D%BC%EC%9D%84%20%EC%86%8D%EC%84%B1%20%EB%AA%A9%EB%A1%9D%EC%9C%BC%EB%A1%9C%20%EC%9D%BD%EA%B8%B0.png)
섹션을 지원하는 것에 대해 걱정하지 않습니다. 그렇게 하면 포상금이 주어질 것입니다. :)
지금까지의 내용은 다음과 같습니다. 그러나 다음과 같은 이상한 출력이 생성됩니다 #2
.
\begin{filecontents}{test}
\Property this property = some value
\Property k = v
\end{filecontents}
\documentclass{article}
\usepackage{expl3}
\ExplSyntaxOn
\cs_new:Npn \Property #1=#2^^M
{
1:#1\par
2:#2\par
}
\ExplSyntaxOff
\begin{document}
\input{test}
\end{document}
이상적으로는 다음과 같은 구문을 갖고 싶습니다.
\begin{filecontents*}{test.conf}
this property = some value
k = v
# bounty
[section]
property=value
\end{filecontents*}
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\begin{document}
\conf_load:Nn \l_tmpa_prop { test.conf }
% outputs {some value} (brace groups irrelevant)
\conf_get:Nn \l_tmpa_prop { this ~ property }
% bounty; outputs {value} (brace groups irrelevant)
\conf_get:Nnn \l_tmpa_prop { section } { property }
\end{document}
이것이 어떻게 이루어질 수 있습니까? 인터페이스/이름 지정의 세부 사항은 단지 제안일 뿐이라는 점에 유의해야 합니다.
아이디어
(진행중인 작업 목록)
- 파일을 읽고 각 줄에 매크로를 매핑합니다. 섹션을 지원하지 않습니다
- 읽기에 필요한 캐릭터를 활성화하고 암흑마법을 연습합니다.
답변1
이것이 당신이 염두에 두고 있는 것입니까?
나는 toplevel
속성 목록과 section
하나를 정의합니다. 필요한 plist를 추가하십시오.
\begin{filecontents*}{test.conf}
this property = some value
k = v
# bounty
[section]
property=value
\end{filecontents*}
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\confload}{m}
{
\allred_conf_load:n { #1 }
}
\prop_new:N \g_allred_conf_toplevel_prop
\prop_new:N \g_allred_conf_section_prop
\tl_new:N \l__allred_level_tl
\ior_new:N \g_allred_read_conf_stream
\cs_new_protected:Npn \allred_conf_load:n #1
{
\group_begin:
\tex_endlinechar:D \c_minus_one % Ugly! Complain with the team!
\char_set_catcode_comment:n { `\# }
\ior_open:Nn \g_allred_read_conf_stream { #1 }
\tl_set:Nn \l__allred_level_tl { toplevel }
\ior_map_inline:Nn \g_allread_read_conf_stream
{
\tl_if_blank:nF { ##1 }
{
\__allred_process_line:x { \tl_trim_spaces:n { ##1 } }
}
}
\ior_close:N \g_allred_read_conf_stream { #1 }
\group_end:
}
\cs_new_protected:Npn \__allred_process_line:n #1
{
\str_case_x:nnF { \tl_item:nn { #1 } { 1 } }
{
{ [ } { \__allred_process_newlevel:n { #1 } }
}
{
\__allred_process_property:n { #1 }
}
}
\cs_generate_variant:Nn \__allred_process_line:n { x }
\cs_new_protected:Npn \__allred_process_newlevel:n #1
{
\__allred_process_newlevel:w #1
}
\cs_new_protected:Npn \__allred_process_newlevel:w [ #1 ]
{
\tl_set:Nn \l__allred_level_tl { #1 }
}
\cs_new_protected:Npn \__allred_process_property:n #1
{
\__allred_process_property_aux:www #1 ==\q_stop
}
\cs_new_protected:Npn \__allred_process_property_aux:www #1 = #2 = #3 \q_stop
{
\prop_gput:cxx { g__allred_conf_ \l__allred_level_tl _prop }
{ \tl_trim_spaces:n { #1 } }
{ \tl_trim_spaces:n { #2 } }
}
\cs_generate_variant:Nn \prop_gput:cnn { cxx }
\ExplSyntaxOff
\begin{document}
\confload{test.conf}
\ExplSyntaxOn
\prop_show:N \g__allred_conf_toplevel_prop
\prop_show:N \g__allred_conf_section_prop
\ExplSyntaxOff
\end{document}
이것은 터미널의 출력입니다.
The property list \g__allred_conf_toplevel_prop contains the pairs (without
outer braces):
> {this property} => {some value}
> {k} => {v}.
<recently read> }
l.78 \prop_show:N \g__allred_conf_toplevel_prop
?
The property list \g__allred_conf_section_prop contains the pairs (without
outer braces):
> {property} => {value}.
<recently read> }
l.79 \prop_show:N \g__allred_conf_section_prop
답변2
내 솔루션은 expl3이나 특수 라텍스 매크로를 사용하지 않고 TeX 프리미티브만 사용합니다. 단지 비교를 위해서입니다. 이 작업의 코딩은 11번째 줄부터 시작됩니다(처음 10개 줄은 OPmac의 범용 매크로로 복사됩니다).
\bgroup \catcode`!=3 \catcode`?=3 % \replacestrings, \addto, \sxdef from OPmac
\gdef\replacestrings#1#2{%
\long\def\tmp##1#1##2!{\ifx!##2!\addto\tmpb{##1}\else\addto\tmpb{##1#2}\tmp##2!\fi}%
\edef\tmpb{\expandafter}\expandafter\tmp\tmpb?#1!%
\def\tmp##1?{\def\tmpb{##1}}\expandafter\tmp\tmpb
}
\egroup
\long\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}
\def\sxdef#1{\expandafter\xdef\csname#1\endcsname}
% \readconf config_file
\newread\infile
\def\readconf #1 {\bgroup \catcode`\#=14 \endlinechar=-1
\def\sectionconf{global}\openin\infile=#1 \readconfA
}
\def\readconfA{\ifeof\infile \egroup \else
\read\infile to\tmp
\expandafter\readconfB\tmp\par
\expandafter \readconfA\fi
}
\def\readconfB#1\par{\ifx\par#1\par \else \readconfC#1\par \fi}
\def\readconfC#1#2\par{\ifx[#1\expandafter\readconfD \else\expandafter\readconfE\fi#1#2\par}
\def\readconfD[#1]#2\par{\def\sectionconf{#1}}
\def\readconfE#1\par{\def\tmpb{#1}\replacestrings{= }{=}\replacestrings{ =}{=}%
\expandafter\readconfF\tmpb\par}
\def\readconfF#1=#2\par{\setkeyval{#1}{#2}}
\def\setkeyval#1#2{\expandafter\ifx\csname conf:\sectionconf\endcsname\relax
\sxdef{conf:\sectionconf}{}\fi
\sxdef{conf:\sectionconf}{\csname conf:\sectionconf\endcsname{#1}}%
\sxdef{key:\sectionconf:#1}{#2}%
}
% \showconf[section]
\def\showconf[#1]{\def\sectionconf{#1}\message{SECTION [#1]:}%
\expandafter\expandafter\expandafter \showconfA \csname conf:#1\endcsname \relax
}
\def\showconfA#1{\ifx\relax#1\else \showconfB{#1}\expandafter\showconfA\fi}
\def\showconfB#1{\message{{#1} => {\csname key:\sectionconf:#1\endcsname}}}
\readconf test.conf
\showconf [global] % SECTION [global]: {this property} => {some value} {k} => {v}
\showconf [section] % SECTION [section]: {property} => {value}
\end