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

Hi, I would like to scan through a file and replace any comma ',' within " " to pipe '|', but when the input string contains '$' or '(' or ')', my script doesn't work as expected. Appreciate for any help please...Thanks.
Sample input records: ONE,"TWo,2",Three,Four,Five ONE,"$TWo,2",Three,Four,Five ONE,"$TWo2","Three,(3)",Four,Five ONE,"$TWo2","Three,(3",Four,Five Expected output records: ONE,"TWo|2",Three,Four,Five ONE,"$TWo|2",Three,Four,Five ONE,"$TWo2","Three|(3)",Four,Five ONE,"$TWo2","Three|(3",Four,Five Current output: ONE,"TWo|2",Three,Four,Five --> ok, converted ONE,"$TWo,2",Three,Four,Five --> wrong, not converted ONE,"$TWo2","Three,(3)",Four,Five --> wrong, not converted Got error for record 4: Unmatched ( in regex; marked by <-- HERE in m/"Three,( <-- HERE 3"/ at + PerlComma.pl line 20, <> line 4 #!/usr/bin/perl use strict; use warnings; my $line; my @matchlist; my $rplstr; while (<>) { $line=$_; @matchlist = $line =~ m/("[^"]*")/g; for my $matchstr (@matchlist) { $rplstr=$matchstr; $rplstr =~ tr/[,]/[|]/; s:$matchstr:$rplstr:g } print; }
  • Comment on Search & Replace doesn't work with string containing certain special characters
  • Download Code

Replies are listed 'Best First'.
Re: Search & Replace doesn't work with string containing certain special characters
by jellisii2 (Hermit) on Sep 09, 2014 at 11:26 UTC
    Any number of the CSV modules would probably be a safer thing to use... I use Tie::Handle::CSV whenever manipulating such data. Process each row and do whatever you wish with them, including just replacing the delimiter.
Re: Search & Replace doesn't work with string containing certain special characters
by wrog (Friar) on Sep 09, 2014 at 11:03 UTC

    Extracting the quoted strings and then searching for them again is kind of inefficient. Likewise for having to create a new regexp for every single quoted string. Perl goes to a fair amount of trouble to compile a regexp into something that walks through a string; the whole point of that is so that you can re-use that walk routine lots of times.

    Meaning what you really want is a single regexp fixed in advance that gets applied to every line. Bonus points if you can have it be a walk-thingie that only has to do a single pass through the string (which then means you want to think about how you'd do the walk if you had to do it yourself). Try this

    use strict; use warnings; while ( my $line = <DATA> ) { print "# ORIG: $line"; if ($line =~ m/"/g) { $line =~ s/\G([^,"]*(?:"[^"]*"[^",]*)*),/$1|/g; } print "# NEW: $line"; } __DATA__ ONE,"TWo,2",Three,Four,Five ONE,"$TWo,2",Three,Four,"Fi,ve,," ONE,"$TWo2","Three,(3)",Four,Five ONE,"$TWo2","Three,(3",Four,Five
Re: Search & Replace doesn't work with string containing certain special characters
by Anonymous Monk on Sep 09, 2014 at 09:23 UTC

    tr/// does not take character classes, only literal strings and character ranges.

    You need to quote the search string in s/// ...

    cat x.pl; echo ; perl x.pl use strict; use warnings; while ( my $line = <DATA> ) { my $old = $line; my @match = ( $line =~ m/ "( [^"]* )" /gx ) ; #" for my $str ( @match ) { ( my $replace = $str ) =~ tr/,/|/ ; # Search string quoted. $line =~ s/ \Q${str}\E /$replace/gx; } printf "ORIG: %s NEW: %s\n" , $old , $line; } __DATA__ ONE,"TWo,2",Three,Four,Five ONE,"$TWo,2",Three,Four,Five ONE,"$TWo2","Three,(3)",Four,Five ONE,"$TWo2","Three,(3",Four,Five ORIG: ONE,"TWo,2",Three,Four,Five NEW: ONE,"TWo|2",Three,Four,Five ORIG: ONE,"$TWo,2",Three,Four,Five NEW: ONE,"$TWo|2",Three,Four,Five ORIG: ONE,"$TWo2","Three,(3)",Four,Five NEW: ONE,"$TWo2","Three|(3)",Four,Five ORIG: ONE,"$TWo2","Three,(3",Four,Five NEW: ONE,"$TWo2","Three|(3",Four,Five
      It works!! Thank you so much!!!