提取句子中周期性出现的九个以上参数,用于宏中排版

提取句子中周期性出现的九个以上参数,用于宏中排版

下面写出 \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}

在此处输入图片描述

相关内容