Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling

Repeating a substitution

by choroba (Bishop)
on Jan 09, 2018 at 10:39 UTC ( #1206958=perlmeditation: print w/replies, xml ) Need Help??

Inspired by Stack Overflow, again.

A user asked for a (awk or similar) one-liner that would replace a separator by a different one in a file, but only the first N separators should be replaced.

For small Ns, it's easiest to repeat the substitution:

perl -pe 's/,/|/;s/,/|/;s/,/|/'

But, what should one do when they want to replace the first 10 separators?

My first idea was to use a for loop:

perl -pe 's/,/|/ for 1 .. 10' # Oops!

Unfortunately, it doesn't work, as the for creates another local $_ and the substitution happens to the numbers, not the input.

So, my next idea was to use a counter with /e:

perl -pe 's/,/$i++<10 ? "|" : ","/ge'

It works, but is ugly and hard to explain to someone not familiar with Perl.

Another way is to tie the two $_ variables together by aliasing the outer $_ by the inner one:

perl -pe 's/,/|/ for $_, $_'
Again, this works only for small number of substitutions.

But, we can generalize a list of the same things: we can use the x operator in list context! It's short, readable, and follows the DRY principle:

perl -pe 's/,/|/ for ($_) x 10'

($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

Replies are listed 'Best First'.
Re: Repeating a substitution
by Eily (Prior) on Jan 09, 2018 at 11:32 UTC

    If the right side of the substitution is constant, split works well, even if the replacement contains the initial value (eg, turn the 10 first | into ||) perl -nE 'print join q(||o||), split q(:), $_, 3' file (as posted on stackoverflow).

      eg, turn the 10 first | into ||

      The example actually turns the first 2 ":" into "||o||".

        Yes, this was what the OP expected on stack overflow

Re: Repeating a substitution
by LanX (Bishop) on Jan 09, 2018 at 12:12 UTC
    Well you can use a while $n-- instead of for or use an explicit variable to be processed instead of $_.

    But I'd try to use the c modifier, though not sure if it's allowed with s// or restricted to m///

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Wikisyntax for the Monastery

Re: Repeating a substitution
by shmem (Chancellor) on Jan 09, 2018 at 16:43 UTC
    perl -pe 's/,/|/ for ($_) x 10'

    Too obscure. This is of the types of constructs which, while being clever, earn perl the fame of being unreadable. There's way too much knowledge needed for a casual programmer to get things right.

    I wouldn't use a statement modifier in this case, but a loop which uses another variable as loop variable:

    perl -pe 'BEGIN {$n=shift} for my $c (1.. $n){ s/;/|/ }' 10 $files

    edit: the two things to grasp here are

    1. what a BEGIN block is about (good to know)
    2. omitting the my $c would make the implicit loop $_ mask the outer $_
    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
Re: Repeating a substitution in a oneliner (write a program, trt)
by beech (Vicar) on Jan 10, 2018 at 01:41 UTC

    But, what should one do when they want to replace the first 10 separators?

    Write a program? So all you have to do is document how to use it, not explain perl syntax

    cat > trt

    #!/usr/bin/perl -- use strict; use warnings; Main( @ARGV ); exit( 0 ); sub Main { @_ or die Usage(); my( $find, $replace, $ntimes ) = @_; ... } sub Usage { qq{ Usage: trt "," "|" 10 trt ",,,,,,,,,," "||||||||||" Translate n times per line read from standard input, writing to stan +dard output. The usage example replaces the first 10 "," characters with "|". Farts sounds like "trt". }; } ## end sub Usage

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://1206958]
Approved by marto
Front-paged by Corion
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (2)
As of 2018-07-21 17:48 GMT
Find Nodes?
    Voting Booth?
    It has been suggested to rename Perl 6 in order to boost its marketing potential. Which name would you prefer?

    Results (449 votes). Check out past polls.