Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Selective replace based on user input

by LexPl (Sexton)
on Nov 20, 2024 at 16:11 UTC ( [id://11162820]=perlquestion: print w/replies, xml ) Need Help??

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

It might puzzle you as a rather weird goal, but I would like to ask you nevertheless, because it would be extremely helpful to be able to do this :-)

Typically, a search and replace operation $_ =~ s/foo/bar/g; will be executed globally for the input file. Sometimes, you would like to decide for each individual match of the search string whether to replace it or not. This is what I mean by selective replace.

The script should have a loop that for each matching string

  • locates the individual match of the search phrase in the input file,
  • displays it in its context - let's say 5 words before and 5 words after each match,
  • takes user input - maybe simply 'Y' (yes) or 'N' (no) and
  • depending on the input value, either replaces the matching string, if the input == 'Y' or otherwise doesn't replace it,

Would you think that this is feasible? And if yes, how could that be done? How would you interrupt processing, display stuff and take user input from the command line and finally continue processing?

Replies are listed 'Best First'.
Re: Selective replace based on user input
by ikegami (Patriarch) on Nov 20, 2024 at 18:41 UTC

    Assuming you're ok with loading the entire file into memory, you can use the following:

    $str =~ s{$pat}{ prompt( $_, $-[0], $+[0]-$-[0], $&, $repl, $`, $' ) ? $repl : $& }eg
    or
    use String::Substitution qw( interpolate_match_vars last_match_vars ); $str =~ s{$pat}{ my $true_repl = interpolate_match_vars( $repl, last_match_vars() ); prompt( $_, $-[0], $+[0]-$-[0], $&, $true_repl, $`, $' ) ? $true_repl : $& }eg

    The latter supports interpolation of numerical captures such as $1 and ${1} in $repl, though you might need to escape some dollar signs and backslashes.

    It's up to you to provide $str (the contents of the file), $pat (the pattern for which to search as a string or compiled regex), $repl (the replacement string) and prompt.

    Args passed to prompt:

    • $str
    • The position in $str at which the match starts.
    • The length of the match.
    • The substring of $str that matched.
    • The string with which the match will be replaced if prompt returns a true value.
    • The substring of $str that precedes the match. Use however much of it that you want.
    • The substring of $str that follows the match. Use however much of it that you want.

    Have prompt return a true value to replace, or a false value to skip the replacement.

    Update: Added second version and a lot of info.

Re: Selective replace based on user input
by jdporter (Paladin) on Nov 20, 2024 at 16:28 UTC

    Given that it's interactive, why not just use an editor? This task would be pretty trivial in an editor like vim.

Re: Selective replace based on user input -- oneliner
by Discipulus (Canon) on Nov 21, 2024 at 10:54 UTC
    Hello LexPl and my late welcome to the monastery,

    ..the following is not wise nor beuatiful, but it works (added some space for readability and please note windows double quotes!)

    cat lorem.txt Lorem ipsum dolor sit amet, consectetur adipisci elit, sed do eiusmod tempor incidunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet, consectetur adipisci elit, sed do eiusmod tempor incidunt ut labore et dolore magna aliqua. perl -M"5;$S=shift;$R=shift;open $o,'>','new2.txt'" -ne "chomp;if($_=~ +/$S/){print qq/$_ $R?/;($_=$_)=~s/$S/$R/ if<STDIN>=~/y/}print$o $_.$/ +" ipsum REPLACE lorem.txt Lorem ipsum dolor sit amet, consectetur adipisci elit, REPLACE? y Lorem ipsum dolor sit amet, consectetur adipisci elit, REPLACE? n cat new2.txt Lorem REPLACE dolor sit amet, consectetur adipisci elit, sed do eiusmod tempor incidunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet, consectetur adipisci elit, sed do eiusmod tempor incidunt ut labore et dolore magna aliqua.

    L*

    PS after some failure I gave up passing regexes as arguments and toying with perl -s ... -S=ipsum and whatalike

    PPS add -MO=Deparse to see it better:

    perl -MO=Deparse -M"5;$S=shift;$R=shift;open $o,'>','new2.txt'" -ne "c +homp;if($_=~/$S/){print qq/$_ $R?/;($_=$_)=~s/$S/$R/ if<STDIN>=~/y/}p +rint$o $_.$/" sub BEGIN { require 5; () } $S = shift @ARGV; $R = shift @ARGV; open $o, '>', 'new2.txt'; LINE: while (defined($_ = readline ARGV)) { chomp $_; if ($_ =~ /$S/) { print "$_ $R?"; ($_ = $_) =~ s/$S/$R/ if readline(STDIN) =~ /y/; } print $o $_ . $/; } -e syntax OK

    PPPS given perlrun doc inaccurate on -s switch

    perl -M"5;open $o,'>','new2.txt'" -sne "chomp;if($_=~/$S/){print qq/$_ $R?/;($_=$_)=~s/$S/$R/ if<STDIN>=~/y/}print$o $_.$/"  -- -S=ipsum -R=REPLACE lorem.txt

    ..works!

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

      You added some significant restrictions without mentioning them.

      • Matches cannot span lines.
      • Only one replacement will be attempted per line.

      perlrun is silent about the need for "--" before arguments that start with "-", but it's not inaccurate about it.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11162820]
Approved by marto
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others admiring the Monastery: (3)
As of 2025-02-15 13:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found