1

Long story short, I have been using \patchcommand within a \whiledo loop to try to construct a string piece-meal from an old string, inserting certain characters along the way.

I cut off a bit of the original \myText, and define it as \fragment and try to add the fragment onto the end a string macro called \myNewText, for a certain number of iterations.

The problem is, every time \fragment is redefined, all the previous additions I made to \myNewText change with it. I want to find a way to append the current value of \fragment to \myNewText so that \myNewText will not change whenever \fragment does.

Here's a 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}

The code above produces:

H'
Ha'Ha'
Hac'Hac'Hac'
Hac 'Hac 'Hac 'Hac '
Hac e'Hac e'Hac e'Hac e'Hac e'

What I want to produce is:

H'
H'Ha'
H'Ha'Hac'
H'Ha'Hac'Hac
H'Ha'Hac'Hac 'Hac e'

Actually, what the final product I'm working towards is even more complex, but for the purposes of the MWE to illustrate my current problem, that'd do nicely.

2
  • the posted code makes no output and the error ! Undefined control sequence. <argument> ... }{}{\fragment {'}} \par \mynewtext – David Carlisle Jul 9 '20 at 21:40
  • Sorry... Somehow the capitalization got lost in the last \myNewText. I've fixed it now. – fiat96 Jul 9 '20 at 21:43
1

ifthen and xstring commands are not expandable and probably would not be my first choice here (even though I wrote the first of those) however you can expand \fragment before using it by re-arranging the call slightly

enter image description here

\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
2

Sorry, but \patchcommand is not the best tool for the job.

Not knowing your real situation, I'll solve the problem you show.

\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}

enter image description here

1

David Carlisle already proposed passing (via \expandafter) the toplevel-expansion of \fragment to an auxiliary macro called \helper.

The purpose of this auxiliary macro is rather specific.

A more general variation of this approach is combining usage of \expandafter (for obtaining \fragment's toplevel-expansion) with usage of a macro \exchange which does exchange two arguments.

(\helper can be used for one purpose only. The \expandafter-\exchange-technique can be used (even nested) in many situations without the need of defining additional macros.)

\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}

enter image description here

In case \unexpanded of the e-TeX-extensions is available, you can do something like this:

\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}

enter image description here

Btw: In some answers i saw "haec" instead of "hac". Afaik that does make a subtle difference. ;-)

1
  • This will help apply the function I need in other situations, thanks! Re. haec vs. hac: it looks like my off-the-cuff Latin grammar needs some polishing! – fiat96 Jul 10 '20 at 13:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.