Skip to main content
1 of 2
Lukas Lang
  • 34.4k
  • 1
  • 56
  • 99

I can think of one (ugly) way to do it:

Attributes[myHold] = {HoldAll};

expr /.
 f[args__] :> With[
   {res = myHold[args] /. Print -> Echo},
   f @@ res /; True
 ] /.
  HoldPattern[f_ @@ myHold[args__]] :> f[args]
(* Hold[{f[{1, {Echo[1]}}], g[{{{Print[1]}}}]}] *)

The idea is to wrap the contents of f inside a function with HoldAll attribute (not Hold, to be able to identify it uniquely later on). In a first step, the expression is returned with myHold[…] still in place. In a second round of replacements, myHold is stripped out again.

Lukas Lang
  • 34.4k
  • 1
  • 56
  • 99