下面写出 \fun 类型的定义的好方法是什么
\fun{abc1 EDF1 xyz1 efg jkl abc2 EDF2 xyz2 efg jkl abc3 EDF3 xyz3 efg jkl abc4 EDF2 xyz4 ...}
其中参数的数量是事先不知道的,可能是 1,也可能是超过 9 个,比如 12 个,结果如下
abc1 EDF1 \form{xyz1} efg jkl abc2 EDF2 \form{xyz2} efg jkl abc3 EDF3 \form{xyz3} efg jkl abc4 EDF2 \form{xyz4} ...
假设答案的
\form
类型与相同\newcommand{\form}[1]{\emph{#1}}
。但将扩展延迟到最后。以防万一。
可能需要几个嵌套的\def
案例,每个案例采用两个变量,并\if
决定何时停止循环...例如当允许宏使用超过 9 个参数时?或者使用 etoolbox 来获得更好的效果?
如果分隔词 efg jkl 在不同位置并不相同,并且它们的长度一定,则假设 efg jkl <=> 始终有 9 个字符将一个输入与下一个输入分隔开。而 abc EDF xyz 的长度可能不同,但始终是三个独立的词。
澄清:
xyz
可以是任意的。但是句子是周期性的,因为第 3、8、13、18 个单词被\form
换行。如果存在的话。至少有 3 个单词。但是可以是 3,如果不是 3 则为 8,如果不是 8 则为 13,只要需要,当三个单词后面没有分隔符时结束,这些单词都可以不同...但是分隔符“efg jkl”确实会重复,并且可以被捕获以进行解析。
答案1
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\fun}{m}
{
% split the input at the spaces
\seq_set_split:Nnn \l_tmpa_seq { ~ } { #1 }
% use a counter for knowing where we are
\int_zero:N \l_tmpa_int
% map the sequence
\seq_map_inline:Nn \l_tmpa_seq
{% one more step
\int_incr:N \l_tmpa_int
\int_compare:nTF { \int_mod:nn { \l_tmpa_int - 3 } { 5 } = 0 }
{% if we're at the 3rd, 5th, 8th, 13th, ... item, apply \form
\form { ##1 }
}
{% otherwise just deliver the item
##1
}
% if not at the last, add a space
\int_compare:nT { \l_tmpa_int < \seq_count:N \l_tmpa_seq } { ~ }
}
}
\ExplSyntaxOff
\NewDocumentCommand{\form}{m}{\emph{#1}}
\begin{document}
\raggedright
\fun{Non eram nescius Brute cum quae summis ingeniis exquisitaque
doctrina philosophi Graeco sermone tractavissent ea Latinis
litteris mandaremus fore ut hic noster labor in varias
reprehensiones incurreret Nam quibusdam et iis quidem non
admodum indoctis totum hoc displicet philosophari Quidam
autem non tam id reprehendunt si remissius agatur sed tantum
studium tamque multam operam ponendam in eo non arbitrantur
Erunt etiam et ii quidem eruditi Graecis litteris contemnentes
Latinas qui se dicant in Graecis legendis operam malle consumere
Postremo aliquos futuros suspicor qui me ad alias litteras
vocent genus hoc scribendi etsi sit elegans personae tamen
et dignitatis esse negent}
\end{document}
答案2
(显著更新了此答案以允许在参数中使用多个(可扩展的)宏\fun
。)
这是一个基于 LuaLaTeX 的解决方案。它可以处理 参数中的多个可扩展宏。Lua\fun
代码首先将(扩展的)输入字符串拆分为单独的单词,并注意标点符号(如果存在)。然后继续打印它们,将第 3、8、13、18 个单词装入宏中\form
。(从数学上讲,选择标准是单词在表中的位置,模 4,等于 3。)非 ASCII UTF8 编码字符是可以的(因为使用的是unicode.utf8.gmatch
函数而不是“基本”string.gmatch
函数。)
% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{luacode} % for 'luacode' environment and '\luastring' macro
%% Lua-side code
\begin{luacode}
function do_fun ( s )
words = {} -- initialize a Lua table
-- split 's' into constituent words
for word in unicode.utf8.gmatch ( s , "%w+%p?" ) do
table.insert ( words , word )
end
-- apply "form" macro at 3rd, 8th, 13th, etc words
for i = 1 , #words do
if i%5 == 3 then
tex.sprint ( "\\form{"..words[i].."} " )
else
tex.sprint ( words[i].." " )
end
end
end
\end{luacode}
%% TeX-side code
\newcommand\fun[1]{\directlua{do_fun(\luastring{#1})}}
\newcommand\form[1]{\emph{#1}}
\newcommand\blurbA{Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit, vestibulum ut, placerat ac, adipiscing vitae, felis. Curabitur dictum gravida mauris.}
\newcommand\blurbB{Nam arcu libero, nonummy eget, consectetuer id, vulputate a, magna. Donec vehicula augue eu neque. Pellentesque habitant.}
\newcommand\blurbC{abc1 EDF1 xyz1 efg jkl abc2 EDF2 xyz2 efg jkl abc3 EDF3 xyz3 efg jkl abc4 EDF4 xyz4 efg jkl abc5 EDF5 xyz5 efg jkl abc6 EDF6 xyz6 efg jkl abc7 EDF7 xyz7 efg jkl abc8 EDF8 xyz8 efg jkl abc9 EDF9 xyz9 efg jkl abc10 EDF10 xyz10 efg jkl abc11 EDF11 xyz11 efg jkl abc12 EDF12 xyz12 efg jkl abc13 EDF13 xyz13}
\begin{document}
\raggedright
\fun{\blurbA\blurbB\blurbC}
\end{document}
答案3
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{listofitems,tabto}
\newcounter{formtrigger}
\newcommand\form[1]{\emph{#1}}
\newcommand\fun[1]{%
\setsepchar{ }%
\readlist*\funlist{#1}%
\setcounter{formtrigger}{2}%
\foreachitem\x\in\funlist[]{%
\stepcounter{formtrigger}%
\ifnum\theformtrigger=5\relax
\form{\x}\setcounter{formtrigger}{0}%
\else%
\x%
\fi%
\ %
}
}
\begin{document}
\fun{abc1 EDF1 xyz1 efg jkl abc2 EDF2 xyz2 efg jkl abc3 EDF3 xyz3 efg jkl abc4 EDF2 xyz4 ...}
\end{document}
原始答案
该listofitems
包可以非常轻松地获取这些输入,并保留原始标记而无需扩展。
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{listofitems,tabto}
\newcommand\form[1]{\emph{#1}}
\newcommand\fun[1]{%
\setsepchar{ }%
\readlist\funlist{#1}%
\foreachitem\x\in\funlist[]{%
Argument \xcnt{} is\tabto{1.3in}``\detokenize\expandafter{\x}'':
\tabto{2.5in}\x\par
}%
}
\begin{document}
\fun{abc1 EDF1 xyz1 efg jkl abc2 EDF2 xyz2 efg jkl abc3 EDF3 xyz3
efg jkl abc4 EDF2 xyz4 ... abc1 EDF1 \form{xyz1} efg jkl abc2
EDF2 \form{xyz2} efg jkl abc3 EDF3 \form{xyz3} efg jkl abc4
EDF2 \form{xyz4} ...}
\end{document}
如果需要多层解析,比如说这efg jkl
是分离更大参数子组的触发器,那么我们有以下内容(注意:efg jkl
不被视为参数,而是参数分隔符):
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{listofitems,tabto}
\newcommand\form[1]{\emph{#1}}
\newcommand\fun[1]{%
\setsepchar{efg jkl/ }%
\readlist*\funlist{#1}%
\foreachitem\x\in\funlist[]{%
\foreachitem\y\in\funlist[\xcnt]{%
Group \xcnt{} sub-argument \ycnt{} is\tabto{2in}``\detokenize
\expandafter\expandafter\expandafter{\funlist[\xcnt,\ycnt]}'':
\tabto{3.2in}\funlist[\xcnt,\ycnt]\par
}}%
}
\begin{document}
\fun{abc1 EDF1 xyz1 efg jkl abc2 EDF2 xyz2 efg jkl abc3 EDF3 xyz3
efg jkl abc4 EDF2 xyz4 ... abc1 EDF1 \form{xyz1} efg jkl abc2
EDF2 \form{xyz2} efg jkl abc3 EDF3 \form{xyz3} efg jkl abc4
EDF2 \form{xyz4} ...}
\end{document}