#!/usr/bin/perl use strict; # https://perlmonks.org/?node_id=11145971 use warnings; use List::AllUtils qw( nsort_by uniq ); use Path::Tiny; use Text::CSV qw( csv ); my $dir = path( '/tmp/dir.1114597' ); mkdir $dir; my $csv = path( $ARGV[0] // "$dir/11145971,csv" ); path( $csv )->spew( <spew( <[0] } }, $_->[2] for @{ csv( in => "$csv" ) }; my $match = qr/(@{[ join '|', map quotemeta($_), nsort_by { -length } keys %table ]})/i; use Data::Dump 'dd'; dd \%table, $match; path( $ARGV[1] // $dir )->visit( sub # NOTE replaces Find::File { /\.(?:txt|rst|yaml)$/ and search_and_replace($_); }, { recurse => 1 } ); print "\n", $testfile->slurp; # FIXME for debugging sub search_and_replace { my ($target_file) = @_; my $pos = 0; # NOTE replaces whole file for each change my $more = 1; while( $more ) { $target_file->edit( sub { pos($_) = $pos; if( /$match/g ) { my ( $was, $where, $pre, $post ) = ( $1, $-[1], $`, $'); print "\n", $pre =~ s/^.*\n(?=.*\n)//sr, "$old$was$reset", $post =~ s/\n.*?\n\K.*//sr, "\n"; my $replace = ask( $was ); $was eq $replace or substr $_, $where, length $was, $replace; $pos = $where + length $replace; } else { $more = 0 } } ); } } sub ask { my ($was) = @_; my @choices = uniq @{ $table{ lc $was } }; local $| = 1; if( @choices > 1 ) { my $n = 1; printf "%8d. $new%s$reset\n", $n++, $_ for @choices; print " replace '$old$was$reset' with ${new}above pick$reset (or 0 to not change) : "; my $pick = =~ tr/0-9//cdr || 0; 0 <= $pick && $pick <= @choices or $pick = 0; return ($was, @choices)[$pick]; } else { print " replace '$old$was$reset' with '$new@choices$reset' ? yes/no : "; return =~ /y/i ? $choices[0] : $was; } }