有一些相关问题:
但我发现的每篇帖子都要求具体的东西,很难理解哪些部分才是对所有字符/单词应用特定操作的实际需要。假设我们有一个,\newcommand\command1[1]{do something}
我们想对每个字符应用这个,\newcommand\command2[1]{do something}
我们想对每个单词应用哪个。我们该怎么做呢?
答案1
使用expl3
:两个命令都有第二个参数,它是处理字符或单词的模板。
在最后一种情况下,我们需要##1
嵌套调用。
\documentclass{article}
\ExplSyntaxOn
\NewDocumentCommand{\applytoeverychar}{mm}
{
\group_begin:
\tl_set:Nn \l_tmpa_tl { #1 }
\tl_replace_all:Nnn \l_tmpa_tl { ~ } { \c_space_tl }
\cs_set_protected:Nn \__masum_apply:n { #2 }
\tl_map_function:NN \l_tmpa_tl \__masum_apply:n
\group_end:
}
\NewDocumentCommand{\applytoeveryword}{mm}
{
\group_begin:
\seq_set_split:Nnn \l_tmpa_seq { ~ } { #1 }
\cs_set_protected:Nn \__masum_apply:n { #2 }
\seq_set_map:NNn \l_tmpb_seq \l_tmpa_seq { \__masum_apply:n { ##1 } }
\seq_use:Nn \l_tmpb_seq { ~ }
\group_end:
}
\cs_new:Nn \__masum_apply:n {} % initialize
\ExplSyntaxOff
\begin{document}
\applytoeverychar{do something}{\textlangle #1\textrangle}
\applytoeveryword{do something}{\textlangle #1\textrangle}
\applytoeveryword{do something}{\textbar\applytoeverychar{#1}{\textlangle##1\textrangle}\textbar}
\end{document}
答案2
该tokcycle
包 (https://ctan.org/pkg/tokcycle) 设置为循环遍历输入的 token 流并依次处理每个 token。它具有宏和环境形式,并可辨别任何给定的 token 是被归类为“字符”、“组”、“宏”(控制序列)还是“空格”(隐式或显式)。这四个类别中的每一个都可以接收有关如何处理该类型 token 的指令。
常规方法是将处理过的标记收集到标记列表中\cytoks
,然后存储起来,以后再重新使用。这种方法允许在执行宏之前收集宏并处理其参数。如果输入流中的宏实际上没有执行(假设它们只是被去标记化),则\cytoks
可以绕过收集标记的这个阶段,并且可以动态输出标记。
在下面的 MWE 中,字符被设为红色并放在括号中,组内容用斜体表示(而组的标记则单独处理),宏用蓝色表示,空格用绿色可见空格表示。在这种情况下,使用 来\addcytoks
收集标记\cytoks
并不是必需的,因为宏不是执行的,而是被表示的(通过\string
)。但是,我还是会收集它们,因为这是标记循环通常进行的方式。
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{tokcycle,xcolor}
\Characterdirective{\addcytoks{\textcolor{red}{(#1)}}}
\Groupdirective{\addcytoks{\itshape}\processtoks{#1}}
\Macrodirective{\addcytoks{\textcolor{cyan}{\string#1}}}
\Spacedirective{\addcytoks{\textcolor{green}{\textvisiblespace}}}
\begin{document}
\tokcyclexpress{This {is \today's} test.}
\the\cytoks
\end{document}
如果希望一次处理一个单词而不是一个字符,则必须在标记循环中构建逻辑以收集字符,并在遇到开始/结束组、宏和/或空格时转储它们。
因此,逻辑更加详细,但仍然简单明了。
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{tokcycle,xcolor}
\def\theword{}
\newcommand\dumpword{\if\relax\theword\relax\else
\addcytoks{\textcolor{red}{(}}%
\addcytoks[1]{\theword}%
\addcytoks{\textcolor{red}{)}}\fi
\def\theword{}}
\stripgroupingtrue
\Characterdirective{\expandafter\def\expandafter\theword\expandafter
{\theword#1}}
\Groupdirective{\dumpword\groupedcytoks{%
\addcytoks{\itshape}\processtoks{#1}\dumpword}}
\Macrodirective{\dumpword\addcytoks{\textcolor{cyan}{\string#1}}}
\Spacedirective{\dumpword\addcytoks{\textcolor{green}{\textvisiblespace}}}
\newcommand\wordprocessor[1]{%
\tokcyclexpress{#1}%
\dumpword
\the\cytoks
}
\begin{document}
\wordprocessor{This {is \today's} test.}
\end{document}
在较新版本的 中tokcycle
,提供了向前查看输入流中一个标记的功能(在以下 MWE 中,通过\tcpeek
)。利用此功能,可以简化单词收集的逻辑,只需确定输入流的下一个标记是否是另一个字符即可。
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{tokcycle,xcolor}
\def\theword{}
\newcommand\dumpword{%
\addcytoks{\textcolor{red}{(}}%
\addcytoks[1]{\theword}%
\addcytoks{\textcolor{red}{)}}%
\def\theword{}}
\newcommand\addtotheword[1]{%
\expandafter\def\expandafter\theword\expandafter{\theword#1}%
\tcpeek\z
\ifcat A\z\else\ifcat0\z\else\dumpword\fi\fi
}
\Characterdirective{\addtotheword{#1}}
\Groupdirective{\addcytoks{\itshape}\processtoks{#1}}
\Macrodirective{\addcytoks{\textcolor{cyan}{\string#1}}}
\Spacedirective{\addcytoks{\textcolor{green}{\textvisiblespace}}}
\newcommand\wordprocessor[1]{%
\tokcyclexpress{#1}%
\the\cytoks
}
\begin{document}
\wordprocessor{This {is \today's} test.}
\end{document}
对于给定的输入流,此代码将产生与上述相同的结果。