use strict; use warnings; use diagnostics; use autodie; use feature qw/fc/; use Text::CSV_XS; use File::Find; use File::Replace 'replace3'; use List::AllUtils qw( nsort_by uniq ); use Path::Tiny; my ($old, $new, $reset) = map "\e[${_}m", 91, 92, 0; my $csvfile = $ARGV[0]; my %table; open my $fh, '<', $csvfile; my $csv = Text::CSV_XS->new({binary=>1, auto_diag=>2}); while ( my $row = $csv->getline($fh) ) { push @{$table{ fc($row->[0]) }}, $row->[2]; } $csv->eof or $csv->error_diag; close $fh; my $match = qr/(@{[ join '|', nsort_by { -length } keys %table ]})/i; find({ preprocess => \&filter, wanted => \&search_and_replace }, $ARGV[1] ); sub filter { return grep { -d or (-f and ( /\.txt$/ or /\.rst$/ or /\.yaml$/))} @_; } sub search_and_replace { open 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 } } ); # print "\e[33m", $target_file->slurp, "\e[0m"; # FIXME here for testing } close $target_file; } 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 <= @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; } } #### perl searchandreplace.pl ~/spreadsheet.csv ~/targetRepo syntax error at deprecatus3.pl line 81, near "$pick <="