9

I have a paragraph in one part of the .tex file that I want to be duplicated in another part of the .tex file.

I could do ctrl-c, ctrl-v... as easy as that, but then if I modify one place, I will have to do the same for the other.

Is there a way to take a piece of text, in some part of the document, surround it by some reference marker, and then just use this reference marker elsewhere to duplicate the text?

EDIT: I could just do

  \newcommand{\textA}{piece of text}

and then use "\textA" anywhere I want this text to appear.

However, I want "\textA" to be defined in a certain place in the document (in the .tex file). That location appears after the first time I want to use this macro.

Macros can be used only in places in the document after which they were defined, so I can't do that.

  • 2
    That seems to be exactly what macros are for. – Matthew Leingang Dec 20 '13 at 12:52
  • Yes, I agree, especially since macros can be defined anywhere in the document. but I want the text to appear in a later place in the document. I will edit the question. – kloop Dec 20 '13 at 13:06
  • Wherever you need to type for the first time "your special paragraph", type instead: \newcommand\textA{your special paragraph}\textA{}. Later, when you need to repeat it, simply type \textA{}. – JLDiaz Dec 20 '13 at 13:43
  • 1
    place the definition of the calling command in the preamble. then it will be available everywhere in your document. – barbara beeton Dec 20 '13 at 15:26
  • 2
    Perhaps if you explained why you need(?) to define the macro after it is used you'll get better answers. – jon Dec 20 '13 at 16:15
8

You can do:

\newcommand{\mylongtext}{%
    %write your text here...
}

Then every time you want to typeset this text, just type:

\mylongtext
  • but how can I use \mylongtext in a location in the .tex file that appears BEFORE the macro definition? – kloop Dec 20 '13 at 13:09
  • You can't. Define the macro earlier. – marczellm Dec 20 '13 at 13:15
5

One could abuse the .aux file.

\documentclass{article}

\makeatletter
\newcommand\remembertext[2]{% #1 is a key, #2 is the text
  \immediate\write\@auxout{\unexpanded{\global\long\@namedef{mytext@#1}{#2}}}%
  #2%
}

\newcommand\recalltext[1]{%
  \ifcsname mytext@#1\endcsname
    \@nameuse{mytext@#1}%
  \else
    ``??''
  \fi
}
\makeatother

\begin{document}

Here we want \recalltext{foo}.

Next we print \remembertext{foo}{``a nonsense phrase with no verb''}

\end{document}

A version that also warns if some text reference has changed.

\documentclass{article}

\makeatletter
\newif\ifmytext@warning
\newcommand\remembertext[2]{% #1 is a key, #2 is the text
  \ifcsname mytext@#1\endcsname
    \begingroup
    \long\def\@tempa{#2}%
    \expandafter\ifx\csname mytext@#1\endcsname\@tempa
      % didn't change
    \else
      \global\mytext@warningtrue
    \fi
    \endgroup
  \fi
  \immediate\write\@auxout{\unexpanded{\global\long\@namedef{mytext@#1}{#2}}}%
  #2%
}

\newcommand\recalltext[1]{%
  \ifcsname mytext@#1\endcsname
    \@nameuse{mytext@#1}%
  \else
    ``??''
  \fi
}

\AtEndDocument{%
  \ifmytext@warning
    \@latex@warning@no@line{Text references may have changed, rerun}
  \fi
}
\makeatother

\begin{document}

Here we want \recalltext{foo}.

Next we print \remembertext{foo}{``a nonsense phrase with no verb''}

\end{document}
  • I don't think this is abuse of the aux file at all. IMO the whole reason the aux file exists is to allow back-definition like the OP wants (and I didn't realize at first). – Matthew Leingang Jan 8 '14 at 0:27
5

Use the clipboard package to copy and paste content (either in the same document, or across multiple documents).

\documentclass{article}
\usepackage{clipboard}
\begin{document}

  \Copy{MyKey}{piece of text}

  \Paste{MyKey}

\end{document}

Output:

example output

3

Put the text that you want to have in different places in your document, in a separate file (paragraph.tex) and, wherever you need it, use it with

\input{paragraph}
  • I would rather have the text appear in the document. I could use your solution in conjunction with "\begin{filecontents}{paragraph.tex}\end{filecontents}", but this unfortunately can only be defined in the preamble. – kloop Dec 20 '13 at 15:20
  • 1
    @kloop This is the best solution, use the filecontents package to overcome the restrictions you have mentioned. – Yiannis Lazarides Dec 21 '13 at 13:51
2

Here's an answer similar to @jon's . You need to compile twice (which is common anyway to get references right) but don't need to change anything in your document.

Page numbers in the second run may change, which could affect some page references since those are set in the first run. They are less likely to change if your paragraph.tex file starts out with contents approximately as long as what you expect to have there eventually. If that's a real problem I can imagine some workarounds.

\documentclass{article}

\newcommand{\textA}{\input paragraph}

\newcommand{\settextA}[1]{%
\newwrite\delayedtext
\immediate\openout\delayedtext=paragraph.tex
\immediate\write\delayedtext{#1}
\immediate\closeout\delayedtext
% #1 % uncomment to have this text appear where it's defined, too
}

\begin{document}
Here is the delayed text:

\textA

But that text wasn't written until now.

\settextA{
Now is the time for all good folks to come to the aid of the party
}
\end{document}
  • This solution works well, but note that if you have any LaTeX commands in the \settextA{} text, you need to change the #1 to \unexpanded{#1}. And the \input command could perhaps be put inside a \IfFileExists, so even the first run will work correctly. – Karl Ove Hufthammer Aug 31 '16 at 19:44
1

How about this:

\newif\iffirstrun  
\firstruntrue  
\documentclass{article} 
\usepackage[T1]{fontenc}
\usepackage{filecontents}     
\iffirstrun    
  \begin{filecontents*}{\jobname-sub.tex} 
    % leave it empty for the first run...   
  \end{filecontents*}   
\fi  

\begin{document}       
\input \jobname-sub.tex 

\begin{filecontents*}{\jobname-sub.tex}       
blah blah blah  
\end{filecontents*}  

\end{document}

For the first run, leave the \firstruntrue uncommented. Now you create an empty subfile, \jobname-sub.tex: it creates an empty file, then \inputs it, then overwrites it with the new filecontents. Then, for any subsequent run, comment out \firstruntrue, and the subfile will not be overwritten by the preamble version of the subfile, and you'll get your later-in-the-document contents.

You could also do something like a Makefile where your call to (say) pdflatex is either

pdflatex "\newif\iffirstrun\firstruntrue\input{myfile.tex}"

of

pdflatex "\newif\iffirstrun\firstruntrue\input{myfile.tex}"

Then you can do it all without needing to modify the header of your file each time. (However, if this issue is only a problem for the initial run, I can't see the advantage.)

1

With the scontents package it's easy enough to do what you're looking for. All stored in memory, of course, if you prefer external files, you can use the key write-env=file.tex and besides storing them in memory, you can have the content in separate files and then use \input. I prefer to save in memory :)

\documentclass{article}
\usepackage{scontents}
\setupsc{ store-env=mysave, store-cmd=mysave }
\setlength{\parindent}{0pt}
\pagestyle{empty}
\begin{document}
% foo1
  A question foo1  \footnote{footnote :)}

% not show 
\begin{scontents}
  short answer to foo1 with \verb*|some code in verbatim|.
\end{scontents}

% show
\Scontents[print-cmd]{  long explanation of foo1 }

Some text, Some text, Some text

% get stored 
\getstored[1]{mysave}\par

Some text, Some text, Some text

\getstored[2]{mysave}\par

Some text, Some text, Some text

\getstored[1]{mysave}

\end{document}

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.