长话短说,我一直\patchcommand
在使用\whiledo
循环尝试从旧字符串中逐个构建字符串,并在此过程中插入某些字符。
我切掉了原来的一小段\myText
,并将其定义为\fragment
,并尝试将片段添加到名为的字符串宏的末尾\myNewText
,进行一定次数的迭代。
问题是,每次\fragment
重新定义时,我之前添加的所有内容都会\myNewText
随之改变。我想找到一种方法来附加当前值这样\fragment
无论何时\myNewText
都\myNewText
不会改变\fragment
。
以下是 MWE:
\documentclass[]{article}
\usepackage{ifthen}
\usepackage{patchcmd}
\usepackage{xstring}
\newcommand\myText{Hac est sententia.}
\newcommand\myNewText{}
\newcommand\iterations{5}
\newcounter{Completions}
\begin{document}
\whiledo{\theCompletions < \iterations}
{
\stepcounter{Completions}
\StrLeft{\myText}{\theCompletions}[\fragment]
\patchcommand{\myNewText}{}{\fragment{'}}
\myNewText
}
\end{document}
上面的代码产生:
哈哈
哈哈
哈哈哈哈
哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈
哈哈
我想要制作的是:
H'
H'Ha'
H'Ha'Hac'
H'Ha'Hac'Hac
H'Ha'Hac'Hac 'Hac e'
实际上,我正在努力打造的最终产品要更加复杂,但为了通过 MWE 说明我当前的问题,这样做就很好了。
答案1
ifthen
和xstring
命令不可扩展,可能不是我在这里的首选(尽管我写了第一个),但是你可以\fragment
在使用它之前通过稍微重新安排调用来扩展它
\documentclass[]{article}
\usepackage{ifthen}
\usepackage{patchcmd}
\usepackage{xstring}
\newcommand\myText{Hac est sententia.}
\newcommand\myNewText{}
\newcommand\helper[1]{\patchcommand{\myNewText}{}{#1{'}}}
\newcommand\iterations{5}
\newcounter{Completions}
\begin{document}
\whiledo{\theCompletions < \iterations}
{% dont forget comments at eol!!
\stepcounter{Completions}%
\StrLeft{\myText}{\theCompletions}[\fragment]%
\expandafter\helper\expandafter{\fragment}%
\myNewText
}
\end{document}
答案2
抱歉,但\patchcommand
它不是完成这项工作的最佳工具。
在不知道您的真实情况的情况下,我会解决您提出的问题。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\iterations}{mm}
{% #1 = text, #2 = number of iterations
\fiat_iteration:nn { #1 } { #2 }
}
\tl_new:N \l__fiat_iteration_in_tl
\tl_new:N \l__fiat_iteration_out_tl
\cs_new_protected:Nn \fiat_iteration:nn
{
% clear the token list containing the result
\tl_clear:N \l__fiat_iteration_out_tl
% store the input
\tl_set:Nn \l__fiat_iteration_in_tl { #1 }
% replace spaces by \space, for technical reasons
\tl_replace_all:Nnn \l__fiat_iteration_in_tl { ~ } { \space }
% execute some code from 1 to #2
\int_step_inline:nn { #2 }
{% ##1 is the current index
% append to the current list
\tl_put_right:Nx \l__fiat_iteration_out_tl
{
% the initial segment of the input up to index ##1, followed by '
\tl_range:Nnn \l__fiat_iteration_in_tl { 1 } { ##1 } '
}
% output the current list
\tl_use:N \l__fiat_iteration_out_tl \par
}
}
\ExplSyntaxOff
\begin{document}
\iterations{Haec est sententia}{6}
\end{document}
答案3
David Carlisle 已经提议通过\expandafter
将的顶层扩展传递\fragment
给名为 的辅助宏\helper
。
这个辅助宏的用途相当特殊。
这种方法的更通用的变体是将的使用\expandafter
(用于获取的\fragment
顶层扩展)与\exchange
交换两个参数的宏的使用相结合。
(\helper
仅可用于一个目的。--\expandafter
技术\exchange
可以在许多情况下使用(甚至嵌套),而无需定义额外的宏。)
\documentclass{article}
\usepackage{ifthen}
\usepackage{patchcmd}
\usepackage{xstring}
\newcommand\exchange[2]{#2#1}
\newcommand\myText{Hac est sententia.}
\newcommand\myNewText{}
\newcommand\iterations{5}
\newcounter{Completions}
\begin{document}
\whiledo{\theCompletions < \iterations}%
{%
\stepcounter{Completions}%
\StrLeft{\myText}{\theCompletions}[\fragment]%
\expandafter\exchange\expandafter{\expandafter{\fragment{'}}}{\patchcommand{\myNewText}{}}%
\myNewText
}
\end{document}
如果\unexpanded
e-TeX 扩展可用,您可以执行以下操作:
\documentclass[]{article}
\usepackage{ifthen}
\usepackage{patchcmd}
\usepackage{xstring}
\newcommand\myText{Hac est sententia.}
\newcommand\myNewText{}
\newcommand\iterations{5}
\newcounter{Completions}
\begin{document}
\whiledo{\theCompletions < \iterations}%
{%
\stepcounter{Completions}%
\StrLeft{\myText}{\theCompletions}[\fragment]%
\begingroup
\edef\myNewText{\noexpand\patchcommand{\noexpand\myNewText}{}{\unexpanded\expandafter{\fragment}{'}}}%
\expandafter\endgroup\myNewText
\myNewText
}%
\end{document}
顺便说一句:在一些答案中我看到的是“haec”而不是“hac”。据我所知,这确实有微妙的区别。;-)