如何将宏的当前值存储为永久字符串?

如何将宏的当前值存储为永久字符串?

长话短说,我一直\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

ifthenxstring命令不可扩展,可能不是我在这里的首选(尽管我写了第一个),但是你可以\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}

在此处输入图片描述

如果\unexpandede-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”。据我所知,这确实有微妙的区别。;-)

相关内容