24

I'd like to write something like this:

\replace{Text should be replaced here, here and here}{here}{Latex}

It should output

Text should be replaced Latex, Latex and Latex

How can this be done?

Andrew Swann
  • 95,762
Marian
  • 243
  • 2
    Welcome to TeX.SX! What about there? Should here be replaced too, to give tLatex? – egreg Nov 25 '14 at 16:19
  • There are probably more than one approach for this. –  Nov 25 '14 at 16:22
  • @egreg In my case I will be replacing a keyword that doesn't occur in arbitrary text, so it doesn't matter. – Marian Nov 25 '14 at 16:22
  • @egreg Updated the question. I'm looking for a way to replace 'eqn' and 'eqn.' (and 'eqn,') – Marian Nov 25 '14 at 17:29
  • I can't understand why you'd want to replace the “keyword”: why not simply type the equation where it belongs? – egreg Nov 25 '14 at 17:32
  • I'd like to use my \theorem command multiple times and define how it will look at one place, for all equations at once. – Marian Nov 25 '14 at 17:36
  • I found a soultion using regular expressions (like you did in your answer). I also deleted all unnececary edits from my question again to make it more helpful for other peole. – Marian Nov 25 '14 at 19:02
  • 1
    @Marian You may ask a new question about your real problem; I believe there are better ways to deal with it. – egreg Nov 25 '14 at 20:57
  • I have a solution now so anything I'd post here wouldn't be a question and probably considered spam. I can post my solution to pastebin if you want. – Marian Nov 25 '14 at 21:07
  • Too literal? \newcommand*{\replace}[3]{Text should be replaced \LaTeX{}, \LaTeX{} and \LaTeX{}} – Benjamin McKay Nov 28 '14 at 19:26

5 Answers5

29

enter image description here

\def\replace#1#2#3{%
 \def\tmp##1#2{##1#3\tmp}%
   \tmp#1\stopreplace#2\stopreplace}
\def\stopreplace#1\stopreplace{}

\replace{Text should be replaced here, here and here}{here}{Latex}

\bye

written as plain tex but would work in latex too.

David Carlisle
  • 757,742
  • This is very elegant and the best answer here, congratulations. Unfortunately it is impossible to use such replacing on the token strings when we needn't to expand the tokens. – wipet Dec 03 '14 at 19:14
  • Is there any way to make the code replace -- (works great) but not ---? – abukaj Mar 21 '23 at 17:02
  • 1
    @abukaj only by hiding --- as {---} or similar – David Carlisle Mar 21 '23 at 17:26
  • But then I wouldn't be able to replace --- without removing the braces, am I right? – abukaj Mar 21 '23 at 17:34
  • @abukaj right. but this site doesn't really support discussion threads on years old answers, if you have a question, better to post a question – David Carlisle Mar 21 '23 at 17:37
  • I have already posted: https://tex.stackexchange.com/questions/680303/how-to-convert-a-dash-to-a-minus-for-ats-only – abukaj Mar 21 '23 at 17:39
21

This uses the higher-level macro StrSubstitute from xstring package. Use [0] as first optional parameter to replace all occurences of here, but as egreg stated in a comment, it will also replace in words like where or there

\documentclass{article}

\usepackage{xstring}




\begin{document}

\StrSubstitute[0]{Text should be replaced here, here and here}{here}{Latex}
\end{document}

enter image description here

21

A complex solution that only replaces complete words:

\documentclass{article}
%\usepackage{xparse,l3regex}% remove with recent LaTeX releases

\ExplSyntaxOn \NewDocumentCommand{\replace}{mmm} { \marian_replace:nnn {#1} {#2} {#3} }

\tl_new:N \l_marian_input_text_tl \tl_new:N \l_marian_search_tl \tl_new:N \l_marian_replace_tl

\cs_new_protected:Npn \marian_replace:nnn #1 #2 #3 { \tl_set:Nn \l_marian_input_text_tl { #1 } \tl_set:Nn \l_marian_search_tl { #2 } \tl_set:Nn \l_marian_replace_tl { #3 } \regex_replace_all:nnN { \b\u{l_marian_search_tl}\b } { \u{l_marian_replace_tl} } \l_marian_input_text_tl \tl_use:N \l_marian_input_text_tl } \ExplSyntaxOff

\begin{document}

\replace{Text should be replaced here, here and here}{here}{\LaTeX{}}

\replace{Text should be replaced here, here and not there}{here}{\LaTeX{}}

\end{document}

enter image description here

A simpler solution that replaces all occurrences:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn \NewDocumentCommand{\replace}{mmm} { \marian_replace:nnn {#1} {#2} {#3} }

\tl_new:N \l_marian_input_text_tl

\cs_new_protected:Npn \marian_replace:nnn #1 #2 #3 { \tl_set:Nn \l_marian_input_text_tl { #1 } \tl_replace_all:Nnn \l_marian_input_text_tl { #2 } { #3 } \tl_use:N \l_marian_input_text_tl } \ExplSyntaxOff

\begin{document}

\replace{Text should be replaced here, here and here}{here}{\LaTeX{}}

\replace{Text should be replaced here, here and not there}{here}{\LaTeX{}}

\end{document}

enter image description here

egreg
  • 1,121,712
  • Thank you. Do you know a way to replace this: \replace{\replace{start}{start}{fail}}{fail}{success}\\ \replace{fail,}{fail,}{success} – Marian Nov 25 '14 at 17:14
  • @Marian - I've provided an answer that sets up the macro \replace so that the result of \replace{\replace{start}{start}{fail}}{fail}{success} is correct, viz., "success". – Mico Nov 25 '14 at 20:48
  • Got LaTeX Error: Filel3regex.sty' not found.. Proposed walkaround:\usepackage{xparse,expl3}` (from https://tex.stackexchange.com/a/491456/123888) – abukaj Mar 21 '23 at 15:02
  • 1
    @abukaj Since 2014 things have changed and loading xparse or l3regex is no longer necessary. – egreg Mar 21 '23 at 16:05
  • Indeed, thanks. :) How can I make your (former) code \replace{Mar.~19 -- Mar. 23}{--}{TO} result in Mar.~19 TO Mar. 23? – abukaj Mar 21 '23 at 16:35
16

Here's a LuaLaTeX-based solution. It uses Lua's powerful string.gsub function in the definition of the \replace macro. The macro \replace can be used recursively.

enter image description here

% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{luacode} % for luacode environment and \luastring macro

%% Lua-side code
\begin{luacode}
function myreplace(s,a,b)
  x = string.gsub(s,a,b)
  tex.sprint ( x )
end
\end{luacode}

%% TeX-side code
\newcommand\replace[3]{\directlua{%
  myreplace( \luastring{#1}, \luastring{#2}, \luastring{#3} ) }}

\begin{document}
\replace{Text should be replaced here, here and here.}{here}{Latex}

\replace{\replace{start}{start}{fail}}{fail}{success}

\replace{fail,}{fail,}{success}
\end{document}

Addendum to address the follow-up query by @user61681: If you must replace every single instance of "here" with "LaTeX" in the entire document, and if you can't do so by performing a global search-and-replace operation in your text editor, the following approach may be of interest. It "works" by (a) setting up a Lua function that employs the string.gsub function to replace all instances of "here" with "LaTeX" and (b) assigning this Lua function to LuaTeX's process_input_buffer callback, in effect making it act like a preprocessor on the input stream before TeX starts doing any of its usual work.

Note that this approach will fail is your document contains macros or labels that contain the string here.

% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{luacode} 
\begin{luacode}
function myreplace ( s )
   s = s:gsub ( "here" , "LaTeX" ) 
   return s 
end
\end{luacode}
\AtBeginDocument{\directlua{luatexbase.add_to_callback(
   "process_input_buffer", myreplace , "myreplace" )}}

\begin{document}
Text should be replaced here, here and here.
\end{document}
Mico
  • 506,678
  • 1
    How to edit this if I want it for whole tex document. The problem is to replace here by LaTeX everywhere. Of course I can include whole text in curly braces after \replace but something simple may be possible. The question is how to extend this to whole tex document. – user61681 Jul 17 '19 at 15:25
  • @user61681 - Please see the addendum I just posted. – Mico Jul 17 '19 at 16:21
  • Thanks. It works. – user61681 Jul 17 '19 at 18:01
4

OpTeX provides the macro \replstring\macro{from}{to}. For example:

\def\replace#1#2#3{\def\tmp{#1}\replstring\tmp{#2}{#3}\tmp}

\replace{Text should be replaced here, here and here}{here}{\OpTeX}

\replace{Text should be replaced here, here and not there}{here}{\OpTeX}

\bye

prints:

Text should be replaced OpTEX, OpTEX and OpTEX

Text should be replaced OpTEX, OpTEX and not tOpTEX

wipet
  • 74,238