为了避免XY问题,我将描述我正在寻找的内容(X)以及我在尝试 X 时发现的问题(Y)。需要说明的是:我并不是想解决 Y 问题,只要能解决 X 问题,我就会非常感激。
我正在寻找
我想定义一个接受字符串作为参数的宏,并且它每页显示给定数量的字符(通过调用任意宏)直到字符串完全遍历。
以下是示例:假设字符串为abcdefghijk
,每页显示字符数为 3 ,\foo
每个字符调用一个宏。生成的文档应如下所示。
\documentclass{article}
\newcommand\foo[1]{Hello #1}
\begin{document}
\foo{a} \foo{b} \foo{c}
\newpage
\foo{d} \foo{e} \foo{f}
\newpage
\foo{g} \foo{h} \foo{i}
\newpage
\foo{j} \foo{k}
\newpage
\end{document}
我想出了以下伪代码:
1. While the original string is not empty:
1.1. Create a substring from the first character to the third character.
1.2. Remove the first three characters from the original string.
1.3. For every character in the substring:
1.3.1. Call \foo{character}
1.4. Call \newpage
我的尝试
对于步骤 1.2,原始字符串需要设置为其自身的子字符串,因此我尝试使用包中的\mystring
将其设置为其自身的子字符串,但出现了错误。\substring
stringstrings
Use of \\substring doesn't match its definition.
\documentclass{article}
\usepackage{stringstrings}
\usepackage{xstring}
\begin{document}
% An arbitrary string
\def\mystring{abcdef}
% We obtain the length so that we can create a substring from the 4th
% character to the end of the string.
\StrLen{\mystring}[\mystringlen]
% When I try to display the string, I get the following error:
% ! Use of \\substring doesn't match its definition.
% \kernel@ifnextchar ...rved@d =#1\def \reserved@a {
% #2}\def \reserved@b {#3}\f...
% l.14 \mystring
%
% ?
\def\mystring{\substring{\mystring}{4}{\mystringlen}}
\mystring
\end{document}
我觉得有一种更简单的方法来实现我上面解释的伪代码。
答案1
我将文本按字素逐个拆分成一个序列,然后使用索引映射该序列,因此在指定数量的项目之后\newpage
会发出命令。每个项目都根据作为第三个参数指定的模板进行包装。
\documentclass{article}
\usepackage[paperwidth=3cm,paperheight=4cm]{geometry} % just for smaller pictures
\ExplSyntaxOn
\NewDocumentCommand{\partitionstring}{mm+m}
{% #1 = number of characters in the substrings
% #2 = string
% #3 = what to do to each item
\rdrg_partition:nnn { #1 } { #2 } { #3 }
}
\seq_new:N \l_rdrg_partition_items_seq
\cs_new_protected:Nn \rdrg_partition:nnn
{
\seq_clear:N \l_rdrg_partition_items_seq
\text_map_inline:nn { #2 } { \seq_put_right:Nn \l_rdrg_partition_items_seq { ##1 } }
\cs_set:Nn \__rdrg_partition_do:n { #3 }
\seq_map_indexed_inline:Nn \l_rdrg_partition_items_seq
{
\__rdrg_partition_do:n { ##2 }
\bool_lazy_or:nnT
{ \int_compare_p:n { \int_mod:nn { ##1 } { #1 } == 0 } } % specified interval
{ \int_compare_p:n { ##1 == \seq_count:N \l_rdrg_partition_items_seq } } % end
{ \clearpage }
}
}
\ExplSyntaxOff
\begin{document}
\partitionstring{3}{abćdefghìjk}{\fbox{#1}\par}
\raggedright Text on a new page
\end{document}
答案2
假设您想要的是字素而不是字节/字符(例如保留重音符号、正确处理 8 位输入):
\documentclass{article}
\ExplSyntaxOn
\NewDocumentCommand \blockstring { O{3} m m }
{ \rdrg_block_string:nnN {#1} {#2} #3 }
\int_new:N \l__rdrg_block_int
\tl_new:N \l__rdrg_block_tl
\cs_new_protected:Npn \rdrg_block_string:nnN #1#2#3
{
\group_begin:
\int_zero:N \l__rdrg_block_int
\tl_clear:N \l__rdrg_block_tl
\text_map_inline:nn {#2}
{
\int_incr:N \l__rdrg_block_int
\tl_put_right:Nn \l__rdrg_block_tl {##1}
\int_compare:nNnT \l__rdrg_block_int = {#1}
{
\int_zero:N \l__rdrg_block_int
\exp_args:NV #3 \l__rdrg_block_tl
\tl_clear:N \l__rdrg_block_tl
}
}
\tl_if_empty:NF \l__rdrg_block_tl
{ \exp_args:NV #3 \l__rdrg_block_tl }
\group_end:
}
\begin{document}
\blockstring{abcdefghijklmnopqrstuvwxyz}\fbox
\end{document}
答案3
以下是我使用 TeX 原语的解决方案尝试:
\newcount\subnum
\newcount\subnumA
\def\processdata#1{\subnum=#1 \subnumA=0 \expandafter\processdataA\data\end}
\def\processdataA#1{\ifx\end#1\newpage\else
\foo{#1}\space
\advance\subnumA by1
\ifnum\subnumA<\subnum \else \newpage \subnumA=0 \fi
\expandafter\processdataA \fi
}
\def\foo#1{Hello #1}
\def\data{abcdefghijk}
\processdata{3} % executes \foo{a} \foo{b} \foo{c} \newpage \foo{d} ... etc.
答案4
这是一个标记循环方法。虽然此 MWE 假设输入\data
都是字符(没有空格、宏或组),但可以轻松修改该方法以将这些考虑在内。
这里,为了方便查看,我将其定义\triggeraction
为\par\hrulefill\par
而不是。\newpage
\documentclass{article}
\usepackage{tokcycle}
%
\newcommand\foo[1]{\fbox{#1}}
\newcommand\triggerindex{3}
\newcommand\triggeraction{\par\hrulefill\par}
%
\newcounter{myindex}
\Characterdirective{\addcytoks{%
\foo{#1}\stepcounter{myindex}\ifnum\value{myindex}=\triggerindex\relax
\triggeraction\setcounter{myindex}{0}\fi
}}
\newcommand\processfoo[1]{%
\setcounter{myindex}{0}%
\expandafter\tokencyclexpress#1\endtokencyclexpress
\clearpage
}
\begin{document}
\def\data{abcdefghijk}
\processfoo{\data}
After text
\end{document}