我想使用我在这个有趣的讨论。
这个想法是可以轻松选择不同的简单效果。不幸的是,下面的代码有一些我无法克服的限制:它不接受空格、重音符或宏。
\documentclass[12pt]{article}
\usepackage{graphicx}
\usepackage{lcg}
% decoration
\def\efect{}
\def\decorate#1#2{\reinitrand[first=-#1,last=#1]\aux#2\end}
\def\aux#1{%
\ifx\end#1
\else
\efect#1%
\expandafter\aux
\fi}
% efects
\newcommand{\jumpingbox}[1]{\rand\raisebox{\therand pt}{\fbox{#1}}}
\newcommand{\rotationbox}[1]{\rand\rotatebox{\therand}{\fbox{#1}}}
\begin{document}
\noindent
\let\efect\jumpingbox
\decorate{2}{The quick brown fox jumps}\\
\let\efect\rotationbox
\decorate{10}{The quick brown fox jumps}\\
\decorate{10}{{{The}}{{quick}}{{brown}}{{fox}}{{jumps}}{{\dots}}}
\end{document}
笔记:
- 上述链接中的其他解决方案均不支持重音符号(我想也不支持 utf-8 输入编码)。它们中的大多数也不支持空格。
- 不知何故,我还会有“逐字逐句”的功能。
- 对我来说,研究 TeX 代码很有教育意义。它看起来像一个简单的递归程序。然而,我怀疑它里面可能隐藏着一个非常黑暗的世界。
- 我的尝试:
为空格添加条件句
\if#1 %
{ }
\else
\efect#1%
\fi
以及一个可怕的语法来调用它
\decorate{2}{The{ }quick{ }brown{ }fox{ }jumps{
over{ }Mar{{í}}a}\\ % <- note the accentuated 'i'
这些措施虽然可以部分解决问题,但显然不能作为万全之策。
答案1
您可以用空格分隔参数\aux
,这样它就逐字进行操作,而不是逐个标记进行操作(这就是它不适用于重音字符的原因:它们由多个标记组成)。
\documentclass[12pt]{article}
\usepackage{graphicx}
\usepackage{lcg}
% decoration
\def\effect{}
\def\decorateEND{\decorateEND}
\edef\decorate#1#2{%
\noexpand\reinitrand[first=-#1,last=#1]%
\noexpand\decorateAUX#2 %
\noexpand\decorateEND\space}
\def\decorateAUX#1 {%
\ifx\decorateEND#1%
\else
\effect{#1}%
\expandafter\decorateAUX
\fi}
% effects
\newcommand{\jumpingbox}[1]{\rand\raisebox{\therand pt}{\fbox{#1}}}
\newcommand{\rotationbox}[1]{\rand\rotatebox{\therand}{\fbox{#1}}}
\begin{document}
\noindent
\let\effect\jumpingbox
\decorate{2}{The quick brown fox jumps}\\
\let\effect\rotationbox
\decorate{10}{The quick brown fox jumps}\\
\decorate{10}{The quick brown fox jumps \dots}\\
\decorate{10}{The quick brown fox jumps over María}
\end{document}
expl3
提供了方便的工具来映射列表并获取随机数。您可以使用 分割空格中的输入\seq_set_split:Nnn
,然后使用 循环遍历该列表\seq_map_inline:Nn
,应用\effect
。然后使用\int_rand:nn {min} {max}
在该间隔内生成一个随机数。代码非常简单:
\documentclass[12pt]{article}
\usepackage{graphicx}
\usepackage{xparse}
\newcommand\effect{}
\ExplSyntaxOn
\NewDocumentCommand \decorate { m m }
{ \emoro_decorate:nn {#1} {#2} }
\seq_new:N \l__emoro_words_seq
\cs_new_protected:Npn \emoro_decorate:nn #1 #2
{
\seq_set_split:Nnn \l__emoro_words_seq { ~ } {#2}
\seq_map_inline:Nn \l__emoro_words_seq
{ \effect { \int_rand:nn {-#1} {#1} } {##1} }
}
\ExplSyntaxOff
% efects
\newcommand{\jumpingbox}[2]{\raisebox{#1pt}{\fbox{#2}}}
\newcommand{\rotationbox}[2]{\rotatebox{#1}{\fbox{#2}}}
\begin{document}
\noindent
\let\effect\jumpingbox
\decorate{2}{The quick brown fox jumps}\\
\let\effect\rotationbox
\decorate{10}{The quick brown fox jumps}\\
\decorate{10}{The quick brown fox jumps \dots}\\
\decorate{10}{The quick brown fox jumps over María}
\end{document}
要逐个字母而不是逐个标记地工作,您需要进行一些解析。在 XeTeX 或 LuaTeX 中,这很简单,因为引擎本身支持 Unicode,i
并且í
和ι
都是单个标记,因此您只需检测空格即可。在 pdfTeX 中,重音字母í
由两个标记组成,它们映射到 的 UTF8 代码点í
。
例如í
,“特殊”字符 会扩展为\UTFviii@two@octets <byte>
或\UTFviii@three@octets <byte>
或 之类的内容\UTFviii@four@octets <byte>
,这告诉我们正在查看的字母由多少个字节组成。一旦我们知道了,我们就可以抓取该数量的标记并将它们一起传递给\effect
。
在下面的代码中,这是在 中完成的\__emoro_decorate_token:N
。\tl_case:NnTF
测试查看当前标记的扩展,如果它以任一开头,\UTFviii@<some>@octets
则它会调用适当的宏来获取字符的剩余部分并将其传递给\effect
。其余代码只是循环遍历参数标记列表并分离单个字符、空格和分组标记(您可以找到此循环机制的简要说明这里和这里)您可以使用其他您喜欢的循环机制。
\documentclass[12pt]{article}
\usepackage{graphicx}
\usepackage{xparse}
\newcommand\effect{}
\makeatletter
\ExplSyntaxOn
\NewDocumentCommand \decoratewords { m m }
{ \emoro_decorate_words:nn {#1} {#2} }
\seq_new:N \l__emoro_words_seq
\cs_new_protected:Npn \emoro_decorate_words:nn #1 #2
{
\seq_set_split:Nnn \l__emoro_words_seq { ~ } {#2}
\seq_map_inline:Nn \l__emoro_words_seq
{ \effect {#1} {##1} }
}
%
\NewDocumentCommand \decorateletters { m m }
{ \emoro_decorate_letters:nn {#1} {#2} }
\tl_new:N \l__emoro_parm_tl
\tl_new:N \l__emoro_output_tl
\cs_new_protected:Npn \emoro_decorate_letters:nn #1 #2
{
\tl_set:Nn \l__emoro_parm_tl {#1}
\tl_clear:N \l__emoro_output_tl
\__emoro_decorate_loop:w #2
\q_recursion_tail \q_recursion_stop
}
\cs_new_protected:Npn \__emoro_decorate_loop:w #1 \q_recursion_stop
{
\tl_if_head_is_N_type:nTF {#1}
{ \__emoro_decorate_token:N }
{
\tl_if_head_is_group:nTF {#1}
{ \__emoro_decorate_group:n }
{ \__emoro_decorate_space:w }
}
#1 \q_recursion_stop
}
\cs_new_protected:Npn \__emoro_decorate_token:N #1
{
\quark_if_recursion_tail_stop_do:Nn #1
{ \tl_use:N \l__emoro_output_tl }
\exp_args:NNo \exp_args:No \tl_case:NnTF
{ \exp_after:wN \tl_head:w #1 \q_stop }
{
{ \UTFviii@two@octets } { \__emoro_UTFviii_two:NNw }
{ \UTFviii@three@octets } { \__emoro_UTFviii_three:NNNw }
{ \UTFviii@four@octets } { \__emoro_UTFviii_four:NNNNw }
}
{#1}
{ \__emoro_add_output:nw { \__emoro_effect:n {#1} } }
}
\cs_new_protected:Npn \__emoro_UTFviii_two:NNw #1 #2
{ \__emoro_add_output:nw { \__emoro_effect:n {#1#2} } }
\cs_new_protected:Npn \__emoro_UTFviii_three:NNNw #1 #2 #3
{ \__emoro_add_output:nw { \__emoro_effect:n {#1#2#3} } }
\cs_new_protected:Npn \__emoro_UTFviii_four:NNNNw #1 #2 #3 #4
{ \__emoro_add_output:nw { \__emoro_effect:n {#1#2#3#4} } }
\cs_new_protected:Npn \__emoro_decorate_group:n #1
{ \__emoro_add_output:nw { \__emoro_effect:n {#1} } }
\exp_last_unbraced:NNo
\cs_new_protected:Npn \__emoro_decorate_space:w { \c_space_tl }
{ \__emoro_add_output:nw { \__emoro_effect:n { ~ } } }
\cs_new_protected:Npn \__emoro_add_output:nw #1 #2 \q_recursion_stop
{
\tl_put_right:Nn \l__emoro_output_tl {#1}
\__emoro_decorate_loop:w #2 \q_recursion_stop
}
\cs_new_protected:Npn \__emoro_effect:n #1
{ \exp_args:NV \effect \l__emoro_parm_tl {#1} }
\cs_new_eq:NN \intrand \int_rand:nn
%
\ExplSyntaxOff
% efects
\newcommand{\jumpingbox}[2]{%
\if\space#2%
\space
\else
\raisebox{\intrand{-#1}{#1}pt}{\fbox{#2}}%
\fi}
\newcommand{\rotationbox}[2]{%
\if\space#2%
\space
\else
\rotatebox{\intrand{-#1}{#1}}{\fbox{#2}}%
\fi}
\begin{document}
\noindent
\let\effect\jumpingbox
\decoratewords{2}{The quick brown fox jumps}\\
\let\effect\rotationbox
\decoratewords{10}{The quick brown fox jumps}\\
\decoratewords{10}{The quick brown fox jumps \dots}\\
\decoratewords{10}{The quick brown fox jumps over María}
\noindent
\let\effect\jumpingbox
\decorateletters{2}{The quick brown fox jumps}\\
\let\effect\rotationbox
\decorateletters{10}{The quick brown fox jumps}\\
\decorateletters{10}{The quick brown fox jumps \dots}\\
\decorateletters{10}{The quick brown fox jumps over María}
\end{document}
答案2
这是一个基于的解决方案这个答案。
\documentclass[12pt]{article}
\usepackage{graphicx}
\usepackage{lcg}
\usepackage{soul}
\makeatletter
\def\SOUL@soeverytoken{%
\efect{\the\SOUL@token}}
\makeatother
\newcommand{\jumpingbox}[1]{\rand\raisebox{\therand pt}{\fbox{#1}}}
\newcommand{\rotationbox}[1]{\rand\rotatebox{\therand}{\fbox{#1}}}
\def\decorate#1#2{\reinitrand[first=-#1,last=#1]\so{#2}}
\begin{document}
\noindent
\let\efect\jumpingbox
\decorate{2}{The quick brown fox jumps}\\
\let\efect\rotationbox
\decorate{10}{The quick brown fox jumps}\\
\decorate{10}{{{The}}{{quick}}{{brown}}{{fox}}{{jumps}}{{\dots}}}
\end{document}
顺便说一句,对于我们猫来说,狐狸不是那快速地。