Expl3 语法:优雅地处理条件/未定义参数

Expl3 语法:优雅地处理条件/未定义参数

在本主题中,编写新命令,用户界面建议请求,你们中的一些人教我如何编写一个可以生成精心设计的标题的函数。

在这种情况下,我的问题很复杂,因为文档中的作者数量可能超过 1。我们计划了一种方法,用于 3 位作者,但该策略非常麻烦。必须为其他作者插入新的节和条件。你教我如何做到这一点,而且很有效,我很感激你的努力。

我目前得到的输出如下所示:

文档标题

作者希望能够轻松排除“指南编号”、“关键字”和“url”部分。他们的建议是保留空白字段,甚至从文档函数调用中省略键。

我希望你告诉我如何让它变得更加灵活。

按照上次的 twoauthors 和 threeauthors 示例,我需要为每个作者创建一个布尔值,然后对输出进行条件化。我摆弄了一下语法,但没能让它工作。但是,即使我能让它工作,我也不太相信这是最好的方法。这太乏味了。

以下是上述 MRE 生成的文档:

\documentclass[11pt,letterpaper,english]{extarticle}
\usepackage{lmodern}
\renewcommand{\sfdefault}{lmss}
\renewcommand{\ttdefault}{lmtt}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[demo]{graphicx}

\usepackage[includehead, includefoot,
lmargin=1in,
rmargin=1in,
tmargin=0.75in,
bmargin=1.0in,
headheight=0pt,
headsep=0pt,
marginparwidth=0pt,
footskip=1.5\baselineskip,
]{geometry}



\usepackage{xcolor}
\definecolor{darkblue}{HTML}{1e2277}


% $ This nullifies emacs subscripting in following%
%%BEGIN: This begins the custom header
\usepackage{array, tabularx}
\usepackage{xparse}
\usepackage{datetime}
\usepackage[unicode=true,pdfusetitle,
bookmarks=true,bookmarksnumbered=false, bookmarksopen=false,
breaklinks=true, pdfborder={0 0 0},
pdfborderstyle={}, backref=false,
colorlinks=true, linkcolor=darkblue, urlcolor=darkblue, 
citecolor=darkblue] {hyperref}


\newdateformat{crmda}{\small{}\textbf{\shortmonthname[\THEMONTH] \THEDAY, \THEYEAR}}


\ExplSyntaxOn
\NewDocumentCommand \guidesetup { +m }
{
  \bool_set_false:N \l_guide_twoauthors_bool
  \bool_set_false:N \l_guide_threeauthors_bool
  \keys_set:nn { guide } { #1 }
}
\keys_define:nn { guide }
{
    firstauthor .code:n = {
      \keys_set:nn { guide / firstauthor } { #1 }
    },
    secondauthor .code:n = {
      \keys_set:nn { guide } { twoauthors }
      \keys_set:nn { guide / secondauthor } { #1 }
    },
    thirdauthor .code:n = {
      \keys_set:nn { guide } { threeauthors }
      \keys_set:nn { guide / thirdauthor } { #1 }
    },
    twoauthors .bool_set:N = \l_guide_twoauthors_bool,
    twoauthors .default:n = true,
    twoauthors .initial:n = false,
    threeauthors .bool_set:N = \l_guide_threeauthors_bool,
    threeauthors .default:n = true,
    threeauthors .initial:n = false,
    firstauthor / firstname .tl_set:N = \l_guide_first_firstname_tl,
    firstauthor / lastname .tl_set:N = \l_guide_first_lastname_tl,
    firstauthor / affiliation .tl_set:N = \l_guide_first_affil_tl,
    firstauthor / email .tl_set:N = \l_guide_first_email_tl,
    secondauthor / firstname .tl_set:N = \l_guide_second_firstname_tl,
    secondauthor / lastname .tl_set:N = \l_guide_second_lastname_tl,
    secondauthor / affiliation .tl_set:N = \l_guide_second_affil_tl,
    secondauthor / email .tl_set:N = \l_guide_second_email_tl,
    thirdauthor / firstname .tl_set:N = \l_guide_third_firstname_tl,
    thirdauthor / lastname .tl_set:N = \l_guide_third_lastname_tl,
    thirdauthor / affiliation .tl_set:N = \l_guide_third_affil_tl,
    thirdauthor / email .tl_set:N = \l_guide_third_email_tl,
    leftlogo .tl_set:N = \l_guide_leftlogo_tl,
    rightlogo .tl_set:N = \l_guide_rightlogo_tl,
    number .int_set:N = \l_guide_number_int,
    title .tl_set:N = \l_guide_title_tl,
    keywords .tl_set:N = \l_guide_keywords_tl,
    url .tl_set:N = \l_guide_url_tl,
    firstauthor .initial:n = { firstname = a, lastname = b,
      affiliation = c, email = d},
    secondauthor .initial:n = { firstname = g, lastname = h,
      affiliation = i, email = j},
    thirdauthor .initial:n = { firstname = g, lastname = h,
      affiliation = i, email = j},
    url .initial:n = {https://ku.edu},
    number .initial:n = 42,
    title .initial:n = {Guide ~ to ~ Guides},
    keywords .initial:n = {guide},
}
\NewDocumentCommand \guidehdr { +o }
{
  \group_begin:
    \IfValueT { #1 } 
    {
      \bool_set_false:N \l_guide_twoauthors_bool 
      \keys_set:nn { guide } { #1 }
    }
    \guide_hdr:
    \group_end:
}
\cs_new_protected:Nn \guide_hdr:
{
  \noindent
  \begin{tabularx}{\textwidth}{|>{\centering\arraybackslash}p{1.25in}>{\centering\arraybackslash}X>{\raggedleft\arraybackslash}p{1.25in}|}
    \hline 
    \begin{minipage}[c]{\linewidth}
      \begin{center}
        \includegraphics[width=\linewidth]{\l_guide_leftlogo_tl}
        \par
        \bigskip
        {\small{}\textbf{Guide ~ No}: ~ \int_to_arabic:n { \l_guide_number_int  }}
      \end{center}%
    \end{minipage} & 
    \begin{minipage}[c][1\totalheight][b]{3.5in}%
      \bigskip
      \begin{center}
        \begin{minipage}[t][1\totalheight][b]{1\columnwidth}%
          \begin{center}
            \textbf{ \large \l_guide_title_tl }\\
            \rule[0.5ex]{1\linewidth}{1pt}
            \par\end{center}%
        \end{minipage}
        \par
      \end{center}
      \begin{minipage}[t]{1\columnwidth}
        \begin{center}
          \textbf{\l_guide_first_firstname_tl {} ~ \l_guide_first_lastname_tl}, ~\l_guide_first_affil_tl {} ~ <\href{mailto:\l_guide_first_email_tl}{\l_guide_first_email_tl} >
          \bool_if:NT \l_guide_twoauthors_bool
          {
            \\
            \textbf{\l_guide_second_firstname_tl {} ~ \l_guide_second_lastname_tl}, ~\l_guide_second_affil_tl {} ~ <\href{mailto:\l_guide_second_email_tl}{\l_guide_second_email_tl} >
          }
          \bool_if:NT \l_guide_threeauthors_bool
          {
            \\
            \textbf{\l_guide_third_firstname_tl {} ~ \l_guide_third_lastname_tl}, ~\l_guide_third_affil_tl {} ~ <\href{mailto:\l_guide_third_email_tl}{\l_guide_third_email_tl} >
          }
          \par
        \end{center}
      \end{minipage}      
      \smallskip
      \par     
      \begin{flushleft}
        \medskip
        \textbf{Keywords}: ~ \l_guide_keywords_tl \\
        See ~ \url{\l_guide_url_tl} ~ for ~ updates.
        \par
      \end{flushleft}
      \smallskip
    \end{minipage} &
    \begin{minipage}[c]{\linewidth}
      \begin{center}
        \includegraphics[width=\linewidth]{\l_guide_rightlogo_tl}
        \par
        \bigskip
        \crmda\today
      \end{center}%
    \end{minipage} 
    \tabularnewline
    \hline 
  \end{tabularx}
}
\ExplSyntaxOff
%%END This ends the custom header



\begin{document}
%% Fill in values of the arguments here, 
%% If blanks are needed, must insert value " ~ "
%% If comma needed inside value, wrap in {}.
%% Delete secondauthor and thirdauthor if not needed
\guidesetup{%
  firstauthor={
    lastname=Author, 
    firstname=First, 
    affiliation=Title{,}~Institute,
    [email protected]},
  secondauthor={
    lastname=Author, 
    firstname=Second, 
    affiliation=Title{,}~Institute, 
    [email protected]}, 
 thirdauthor={
    lastname=Author,
    firstname=Third, 
    affiliation=Title{,}~Institute,
    [email protected]}, 
  url={https://your.website.here.edu/guides},
keywords={knitr, LaTeX, reproducible documents},
  title={A Title for Skeleton Template: rnw2pdf-guide-knit},
  leftlogo={theme/logoleft.pdf},
  rightlogo={theme/logo-vert.pdf},
  number=-1
}
\guidehdr



HOWDY!

\end{document}

答案1

这里尝试了一种更友好的语法;不需要为作者声明不同的键,只需使用一个键和一个属性列表来存储数据。

\documentclass{article}
\usepackage[demo]{graphicx}

\usepackage[includehead, includefoot,
lmargin=1in,
rmargin=1in,
tmargin=0.75in,
bmargin=1.0in,
headheight=0pt,
headsep=0pt,
marginparwidth=0pt,
footskip=1.5\baselineskip,
]{geometry}

\usepackage{xcolor}
\definecolor{darkblue}{HTML}{1e2277}

\usepackage{array}
\usepackage{xparse}
\usepackage{datetime}
\usepackage{hyperref}

\newdateformat{crmda}{{\small\bfseries\shortmonthname[\THEMONTH] \THEDAY, \THEYEAR}}

\ExplSyntaxOn
\NewDocumentCommand \guidesetup { m }
 {
  \keys_set:nn { guide } { #1 }
 }

\int_new:N \g_guide_authors_int
\prop_new:N \g_guide_authors_prop
\tl_new:N \l__guide_authors_tl

\keys_define:nn { guide }
 {
  author .code:n =
   {
    \int_gincr:N \g_guide_authors_int
    \keys_set:nn { guide / author } { #1 }
   },
  author/firstname .code:n = { \guide_add_author:nn { firstname } { #1 } },
  author/lastname .code:n = { \guide_add_author:nn { lastname } { #1 } },
  author/affiliation .code:n = { \guide_add_author:nn { affiliation } { #1 } },
  author/email .code:n = { \guide_add_author:nn { email } { #1 } },
  leftlogo .tl_set:N = \l_guide_leftlogo_tl,
  rightlogo .tl_set:N = \l_guide_rightlogo_tl,
  number .tl_set:N = \l_guide_number_tl,
  title .tl_set:N = \l_guide_title_tl,
  keywords .tl_set:N = \l_guide_keywords_tl,
  url .tl_set:N = \l_guide_url_tl,
  title .initial:n = {TITLE~NEEDED},
}
\NewDocumentCommand \guidehdr { +O{} }
 {
  \group_begin:
  \keys_set:nn { guide } { #1 }
  \guide_hdr:
  \group_end:
 }

\cs_new_protected:Nn \guide_hdr:
 {
  \centering
  \begin{tabular}
   {
    |c
    m{ \dim_eval:n { \textwidth - 2.5in - 6\tabcolsep - 2\arrayrulewidth } }
    c|
   }
  \hline
  &&\tabularnewline[-\dim_eval:n { -\normalbaselineskip + 3ex }]
  \begin{tabular}{@{}c@{}}
  \includegraphics[width=1.25in]{\l_guide_leftlogo_tl} \\[\medskipamount]
  \small\bfseries
  \tl_if_empty:NTF \l_guide_number_tl %<--- there was a typo
   { \leavevmode\vphantom{G} }
   { Guide~No: ~ \tl_use:N \l_guide_number_tl }
  \end{tabular}
  &
  \centering
  \textbf{\large\l_guide_title_tl\\}
  \rule[0.5ex]{1\linewidth}{1pt} \\
  \guide_print_authors:
  \vspace{\bigskipamount}
  \raggedright
  \tl_if_empty:NF \l_guide_keywords_tl
   {
    \textbf{Keywords}: ~ \l_guide_keywords_tl \\
   }
  \tl_if_empty:NF \l_guide_url_tl
   {
    See ~ \url{\l_guide_url_tl} ~ for ~ updates.
   }
  &
  \begin{tabular}{@{}c@{}}
  \includegraphics[width=1.25in]{\l_guide_rightlogo_tl} \\[\medskipamount]
  \small\bfseries
  \crmda\today
  \end{tabular}
  \tabularnewline
  \hline 
  \end{tabular}
}

\cs_new_protected:Nn \guide_add_author:nn
 {
  \prop_gput:Nxn \g_guide_authors_prop
   { #1 \int_to_arabic:n { \g_guide_authors_int } }
   { #2 }
 }
\cs_generate_variant:Nn \prop_gput:Nnn { Nx }
\cs_new_protected:Nn \guide_print_authors:
 {
  \tl_clear:N \l__guide_authors_tl
  \int_step_inline:nnnn { 1 } { 1 } { \g_guide_authors_int }
   {
    \tl_put_right:Nn \l__guide_authors_tl
     {
      \textbf
       {
        \prop_item:Nn \g_guide_authors_prop { firstname ##1 }~
        \prop_item:Nn \g_guide_authors_prop { lastname ##1 }:~
       }
      \prop_item:Nn \g_guide_authors_prop { affiliation##1 }~
      \prop_item:Nn \g_guide_authors_prop { email##1 } \\
     }
   }
   \tl_use:N \l__guide_authors_tl
 }
\ExplSyntaxOff
%%END This ends the custom header



\begin{document}

\guidesetup{%
  author={
    lastname=Author, 
    firstname=First, 
    affiliation=Title{,}~Institute,
    [email protected]},
  author={
    lastname=Author, 
    firstname=Second, 
    affiliation=Title{,}~Institute, 
    [email protected]}, 
  author={
    lastname=Author,
    firstname=Third, 
    affiliation=Title{,}~Institute,
    [email protected]}, 
  url={https://your.website.here.edu/guides},
  keywords={knitr, LaTeX, reproducible documents},
  title={A Title for Skeleton Template: rnw2pdf-guide-knit},
  leftlogo={theme/logoleft.pdf},
  rightlogo={theme/logo-vert.pdf},
  number=-1
}
\guidehdr

\bigskip

\ExplSyntaxOn % for experimenting
\prop_gclear:N \g_guide_authors_prop
\int_gzero:N \g_guide_authors_int
\ExplSyntaxOff

\guidesetup{%
  author={
    lastname=Author, 
    firstname=First, 
    affiliation=Title{,}~Institute,
    [email protected]},
  author={
    lastname=Author, 
    firstname=Second, 
    affiliation=Title{,}~Institute, 
    [email protected]}, 
  url={https://your.website.here.edu/guides},
  title={A Title for Skeleton Template: rnw2pdf-guide-knit},
  leftlogo={theme/logoleft.pdf},
  rightlogo={theme/logo-vert.pdf},
  number=20
}
\guidehdr

\end{document}

在此处输入图片描述

相关内容