http://qs321.pair.com?node_id=1156148

f77coder has asked for the wisdom of the Perl Monks concerning the following question:

Hello,

I need a bit of help, usually for bulk replacement of a word in a bunch of files I do something like this

perl -pi -e 's/junk/replace/g' *.c

but i need to be able to put a conditional || on the search without clobbering, I'm updating old C files to C11 type generic. there are a lot of type specific qualifiers that i want to replace with generic

http://en.cppreference.com/w/c/numeric/tgmath

for example
generic float dbl long cfloat c dbl cmplx long atanh atanhf atanh atanhl catanhf catanh catanhl

so in general i need to check for suffixes and prefixes at the same time otherwise the search term will clobber the previous search.

i need to put a conditional in the search like this
perl -pi -e 's/c$tgt || c$tgtf || c$tgtl || $tgtf || $tgtl /$tgt/g' *. +c

where $tgt is the replacement string, for example

$tgt = tanh

i need to search and replace the following

tanhf  tanhl ctanhf ctanh ctanhl

but i get a complete mess out as the command still recurses and substitutes.

as well as the tricky one to replace 'rint' as it will conflict with printf

these old files have no spaces between operators but i'll space it out

exa=cexpl ( ccosl (arg), csinl ( arg) ) * cabsl (arg2) + csqrtl ( carg +l(arg3) + csqrtl(cargl(arg4) * cargl(arg5) + cargl (arg5) * cargl(arg +5));
result would be
exa = exp( cos(arg) , sin(arg) ) * fabs(arg2)+ sqrt(carg(arg3) + sqrt( +carg(arg4)*carg(arg5)+carg(arg5)*carg(arg5));

Replies are listed 'Best First'.
Re: search/replace one liners without clobbering
by AnomalousMonk (Archbishop) on Feb 25, 2016 at 23:04 UTC

    Some thoughts:

    • There is no  || regex operator. More precisely,  || resolves to a pair of  | regex alternation operators with a null pattern between them, and the  // null regex pattern matches everything, so no surprise about the junk.
    • I don't get where the   $tgt  $tgtf  $tgtl variables are defined and initialized: what are these supposed to represent? Do you have any philosophical objection to running with strict and warnings enabled?
    • (Update: The  /c$tgt || c$tgtf || c$tgtl || $tgtf || $tgtl / regex has embedded literal spaces. I don't know if this is intentional, but you may want to investigate the  /x regex modifier; see Modifiers.)

    Can you supply a short, representative chunk of the sample input data you wish to process and its desired final form? I think that would help greatly to define the problem.

    Update: Various small wording and spelling fixes.


    Give a man a fish:  <%-{-{-{-<

      sure here is an example line of code these old files have no spaces between operators but i'll space it out
      exa=cexpl ( ccosl (arg), csinl ( arg) ) * cabsl (arg2) + csqrtl ( carg +l(arg3) + csqrtl(cargl(arg4) * cargl(arg5) + cargl (arg5) * cargl(arg +5));
      result would be
      exa = exp( cos(arg) , sin(arg) ) * fabs(arg2)+ sqrt(carg(arg3)) + sqrt +(carg(arg4)*carg(arg5)+carg(arg5)*carg(arg5));
        result would be

        exa = exp( cos(arg) , sin(arg) ) * fabs(arg2)+ sqrt(carg(arg3)) + sqrt(carg(arg4)*carg(arg5)+carg(arg5)*carg(arg5));

        Really? Why do you go from cabsl to fabs instead of replacing it with abs? Also, your bracket counts seem to differ between the before and after examples.

        Assuming that you didn't mean that and really wanted abs and the same number of brackets and correcting the arbitrary whitespace:

        #!/usr/bin/env perl use strict; use warnings; use Test::More tests => 1; my $have = 'exa=cexpl ( ccosl (arg), csinl ( arg) ) * cabsl (arg2) + c +sqrtl ( cargl(arg3)) + csqrtl(cargl(arg4) * cargl(arg5) + cargl (arg5 +) * cargl(arg5));'; my $want = 'exa = exp( cos(arg) , sin(arg) ) * abs(arg2)+ sqrt(carg(ar +g3)) + sqrt(carg(arg4)*carg(arg5)+carg(arg5)*carg(arg5));'; # Remove apparently arbitrary spaces for the purposes of validation $have =~ s/ +//g; $want =~ s/ +//g; for my $term (qw/exp cos sin abs sqrt carg/) { $have =~ s/\b[cf]? ${term} [fl]?/$term/xg; } is ($have, $want, 'Match');
Re: search/replace one liners without clobbering
by ExReg (Priest) on Feb 25, 2016 at 23:20 UTC

    Are you looking to strip the c off the front and the f or l off the back?

    perl -e '$tgt =~ s/\bc?(\w+?)(?:f|l)?\b/$1/g;'

    Feed the target token into it to strip off leading c and trailing f or l. Of course, this would make a bool into a boo.

      yes bool would get mangled, also any print f gets mangled as well if rint is replaced.

      cases are

      prefix 'c' OR 'f' OR both or neither suffix, 'l' OR 'f' OR both or neither
        You asked for a oneliner, which by I think you mean to give each function separately, so for "exp", it would be:

        perl -pi -e 's/\bc?${tgt}[fl]?\b/$tgt/g' -s -- -tgt=exp *.c;

        The problem is fabs, which means you need to consider it separately:

        perl -pi -e 'for $tgt(qw(exp log pow sqrt sin cos tan asin acos atan sinh cosh tanh asinh acosh atanh)){ s/\bc?${tgt}[fl]?\b/$tgt/g };s/\b[cf]abs[fl]?\b/fabs/g' *.c;

        addendum, with the | or you wanted, it would be:

        perl -pi -e 's/\bc?(exp|log|pow|sqrt|sin|cos|tan|asin|acos|atan|sinh|c +osh|tanh|asinh|acosh|atanh)[fl]?\b/$1/g; s/\b[cf]abs[fl]?\b/fabs/g'