Skip to content

前两天看到一个模板实现了如下的一个接口

latex
\titleimage{
  chapteroddimage = {odd1,odd2,odd3,odd4,odd5,odd6},
  partoddimage = {odd1,odd2,odd3,odd4,odd5,odd6},
  chapterevenimage = {songeven,even1,even2},
  partevenimage={songeven,even1,even2},
}

功能就是为 part, chapter... 设置背景图片

大概思路是,将

latex
chapterimage = {odd1,odd2,odd3,odd4,odd5,odd6}

这个列表里面的图片名依次赋值到

latex
\@chapter@image@1 -> odd1
\@chapter@image@2 -> odd2
\@chapter@image@3 -> odd3
\@chapter@image@4 -> odd4
...

然后通过

latex
\includegraphics{\@chapter@image@<\value{chapter}>}

<\value{chapter}> 指的是当前 chapter 的计数器的值,这样就能动态的设置每一个 chapter 的背景图片,这个思路不光是可以应用到章节背景图,其它的地方也能适用.

回到问题,现在想要给所有 chapter 都设置成同样的图片,那么就需要如下设置

latex
chapterimage = {
    image, image, image, image, image, image, image, 
    image, image, image, image, image, image, ...
}

这样,其实是会有很多重复的配置

想要把它优化一下,如下

latex
chapter-image = {1, 3-6, 8}{left.png},
chapter-image = {2, 7, 9-12}{right.jpg}

下面就来实现它

首先是需要有一个函数,它需要接受两个参数. 来解析 {2, 7, 9-12}{right.jpg}

latex3
\__module_chapter_image_parser:nn

这个函数要实现的功能是,读取 {2, 7, 9-12},然后定义对应的变量储存

latex3
\g__module_chapter_image_2_tl  -> right.png
\g__module_chapter_image_7_tl  -> right.png
\g__module_chapter_image_9_tl  -> right.png
\g__module_chapter_image_10_tl -> right.png
\g__module_chapter_image_11_tl -> right.png
\g__module_chapter_image_12_tl -> right.png

很简单吧

那么就需要一个辅助函数,用于将 {1-3, 7, 9-12} 转化为 {1, 2, 3, 7, 9, 10, 11, 12}

latex3
\cs_set_nopar:Npn \__module_range_to_list:nN #1#2 {
  \seq_set_split:Nnn \l__module_tmpa_seq { , } { #1 }
  \seq_map_inline:Nn \l__module_tmpa_seq 
  {
    \tl_if_in:nnTF { ##1 }{ - }
    {
      \seq_set_split:Nnn \l__module_tmpb_seq { - } { ##1 }
      \int_step_inline:nnn 
      { \seq_item:Nn \l__module_tmpb_seq { 1 } } 
      { \seq_item:Nn \l__module_tmpb_seq { 2 } } 
      {
        \clist_put_right:Nn #2 { ####1 }
      }
    }
    {
      \clist_put_right:Nn #2 { ##1 }
    }    
  }
}

具体流程为

  • 按逗号 , 分割成列表
  • 遍历该队列
    • 如果存在 -,说明为 1-6 这样的 range,那么按 - 分割,以两端的数字为起始,通过整数循环依次放进目标数组
    • 如果不存在 -,说明为 5 这样的单个数字,直接放进目标数组
  • 返回目标数组

现在就可以遍历上面返回的目标数组完成变量的赋值了

latex3
\cs_set_nopar:Npn \__module_chapter_image_parser:nn #1#2 
{
  \clist_clear:N \l__module_tmpa_clist
  \__module_range_to_list:nN { #1 } \l__module_tmpa_clist
  \clist_map_inline:Nn \l__module_tmpa_clist 
  {
    \tl_gset:cn { g__module_chapter_image_##1_tl } { #2 }
  }
}

使用

latex3
\__module_chapter_image_parser:nn {1, 3-5, 7} {image.png}

就可以实现

latex3
\g__module_chapter_image_1_tl -> image.png
\g__module_chapter_image_3_tl -> image.png
\g__module_chapter_image_4_tl -> image.png
\g__module_chapter_image_5_tl -> image.png
\g__module_chapter_image_7_tl -> image.png

问题又来了,如果就想要每个 chapter 都不一样呢,那岂不是要

latex3
\__module_chapter_image_parser:nn {1} {image1.png}
\__module_chapter_image_parser:nn {2} {image2.png}
\__module_chapter_image_parser:nn {3} {image3.png}
\__module_chapter_image_parser:nn {4} {image4.png}
\__module_chapter_image_parser:nn {5} {image5.png}
\__module_chapter_image_parser:nn {6} {image6.png}
\__module_chapter_image_parser:nn {7} {image7.png}
\__module_chapter_image_parser:nn {8} {image8.png}
...

所以是需要兼容一下这个接口

latex3
\cs_set_nopar:Npn \__module_chapter_image_parser:nn #1#2 
{
  \clist_clear:N \l__module_tmpa_clist
  \tl_if_eq:nnTF { #1 } { * } 
  {
    \clist_set:Nn \l__module_tmpa_clist { #2 }
    \int_step_inline:nn { \clist_count:N \l__module_tmpa_clist } {
      \tl_gset:cn { g__module_chapter_image_##1_tl } 
      {
        \clist_item:Nn \l__module_tmpa_clist { ##1 }
      }
    }
  }
  {
    \__module_range_to_list:nN { #1 } \l__module_tmpa_clist
    \clist_map_inline:Nn \l__module_tmpa_clist 
    {
      \tl_gset:cn { g__module_chapter_image_##1_tl } { #2 }
    }
  }
}

现在就可以

latex3
\__module_chapter_image_parser:nn { * }
{
    image1.png,
    image2.png,
    image3.png,
    image4.png,
    image5.png,
    image6.png,
    ...
}

接下来是将其封装为 key-value 形式

latex3
\keys_define:nn { module }
{
  chapter-image.code:n = \__module_chapter_image_parser:nn #1
}

\NewDocumentCommand{\setup}{ m }{ \keys_set:nn { module } {#1} }

使用方式如下

latex3
\setup{%
  chapter-image = {1, 3-5, 7-9}{image.png},
  chapter-image = {2, 6, 10-15}{cover.jpg},
  % chapter-image = {*}{image1, image2, image3, image4}
}

完整源码如下

latex3
\documentclass{article}

\usepackage[margin = 2cm]{geometry}

\ExplSyntaxOn

\seq_new:N \l__module_tmpa_seq 
\seq_new:N \l__module_tmpb_seq 

\clist_new:N \l__module_tmpa_clist

\cs_set_nopar:Npn \__module_range_to_list:nN #1#2 {
  \seq_set_split:Nnn \l__module_tmpa_seq { , } { #1 }
  \seq_map_inline:Nn \l__module_tmpa_seq 
  {
    \tl_if_in:nnTF { ##1 }{ - }
    {
      \seq_set_split:Nnn \l__module_tmpb_seq { - } { ##1 }
      \int_step_inline:nnn 
      { \seq_item:Nn \l__module_tmpb_seq { 1 } } 
      { \seq_item:Nn \l__module_tmpb_seq { 2 } } 
      {
        \clist_put_right:Nn #2 { ####1 }
      }
    }
    {
      \clist_put_right:Nn #2 { ##1 }
    }    
  }
}

\cs_set_nopar:Npn \__module_chapter_image_parser:nn #1#2 
{
  \clist_clear:N \l__module_tmpa_clist
  \tl_if_eq:nnTF { #1 } { * } 
  {
    \clist_set:Nn \l__module_tmpa_clist { #2 }
    \int_step_inline:nn { \clist_count:N \l__module_tmpa_clist } {
      \tl_gset:cn { g__module_chapter_image_##1_tl } 
      {
        \clist_item:Nn \l__module_tmpa_clist { ##1 }
      }
    }
  }
  {
    \__module_range_to_list:nN { #1 } \l__module_tmpa_clist
    \clist_map_inline:Nn \l__module_tmpa_clist 
    {
      \tl_gset:cn { g__module_chapter_image_##1_tl } { #2 }
    }
  }
}


\keys_define:nn { module }
{
  chapter-image.code:n = \__module_chapter_image_parser:nn #1
}


\NewDocumentCommand{\setup}{m}{ \keys_set:nn { module } {#1} }

\NewDocumentCommand{\showimg}{m}{ \tl_use:c {g__module_chapter_image_#1_tl} }

\ExplSyntaxOff

\begin{document}



\setup{%
  chapter-image = {1, 3-5, 7-9}{image.png},
  chapter-image = {2, 6, 10-15}{cover.jpg},
  % chapter-image = {*}{image1, image2, image3, image4}
}

\showimg{1}

\showimg{4}

\showimg{10}

\end{document}