http://www.perlmonks.org?node_id=1203138

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

Hi Monks!

I have a call to SQL store procedure than I need to filter for single quotes and replace with two single quotes, I am trying to see if there is a way to do this search and replace inside of "map", here is the code sample I am referring to:
If in "$data->{$_}" has a string like; "Maria's" I need it converted to "Maria''s".
my @allparms = qw( letters loc type name zip); my $sql = exec_select( "call store_proc(" . join(',', ('?') x @allparm +s ) . ")", map { $data->{ $_ } || '' } @allparms );

Thanks for looking!

Replies are listed 'Best First'.
Re: Replacing single quotes to two single quotes inside map
by duff (Parson) on Nov 10, 2017 at 21:22 UTC

    Assuming you don't mind changing $data->{$_} directly (rather than making a copy) ...

    my $sql = exec_select( "call store_proc(" . join(',', ('?') x @allparm +s ) . ")", map { $data->{$_} =~ s/'/''/g; $data->{ $_ } | +| '' } @allparms );
      Could you explain the pros and cons about changing $data->{$_} rather than making a copy of it?

        The pros/cons are mostly about whether or not you need the original values of $data->{$_} elsewhere since the substitution operation will change the value in-place. If you require the original value prior to the change elsewhere in your code, then clearly you don't want to change them. tybalt89 gave a similar version where the value is returned and not changed, but it requires a relatively recent perl (>= 5.14). I didn't notice if you mentioned a perl version, but some unfortunate people are still on 5.10.1 and such.

Re: Replacing single quotes to two single quotes inside map
by choroba (Cardinal) on Nov 11, 2017 at 09:02 UTC
    If you're using placeholders (and I guess you are, ('?') seems familiar), then you shouldn't need to replace the single quote.
    #!/usr/bin/perl use warnings; use strict; use feature qw{ say }; use DBI; my $db = 'DBI'->connect('dbi:SQLite:dbname=:memory:', "", ""); $db->do('CREATE TABLE t1 (name VARCHAR)'); my $insert = $db->prepare('INSERT INTO t1 VALUES (?)'); $insert->execute("Maria's"); my $select = $db->prepare('SELECT * FROM t1'); $select->execute; while (my @row = $select->fetchrow_array) { say "@row"; # Maria's }

    ($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,
      Yes, I know that, but I am calling a store procedure that is a DB2 database.
      Wouldn't work with smart quote, single quote from MS Word.
        Ah, so they're storing the smart quote as two single quotes in the DB! Clever.

        ($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,
Re: Replacing single quotes to two single quotes inside map
by tybalt89 (Monsignor) on Nov 10, 2017 at 21:28 UTC
    my @allparms = qw( letters loc type name zip); my $sql = exec_select( "call store_proc(" . join(',', ('?') x @allparm +s ) . ")", map { $data->{ $_ } =~ s/'/''/gr || '' } @allp +arms );

    doesn't change $data->{ $_ }

Re: Replacing single quotes to two single quotes inside map
by thanos1983 (Parson) on Nov 10, 2017 at 21:24 UTC

    Hello Anonymous Monk,

    Try something like that:

    #!/usr/bin/perl use strict; use warnings; use Data::Dumper; my @in = ("Maria's", "Thano's"); my @out = map { s/'/"/g; $_ } @in; print Dumper \@out; __END__ $ perl test.pl $VAR1 = [ 'Maria"s', 'Thano"s' ];

    Update: Got late in my post due to experimentation. Did not copied fellow Monk duff code. Just to avoid confusion.

    Hope this helps, BR.

    Seeking for Perl wisdom...on the process of learning...not there...yet!
      my @out = map { s/'/"/g; $_ } @in;

      This solution has the behavior discussed by duff here and here of also changing the source array:

      c:\@Work\Perl\monks>perl -wMstrict -MData::Dumper -le "my @in = ('Maria-s', 'Thano-s'); my @out = map { s/-/+/g; $_; } @in; print Dumper \@in; print Dumper \@out; " $VAR1 = [ 'Maria+s', 'Thano+s' ]; $VAR1 = [ 'Maria+s', 'Thano+s' ];
      If this is acceptable, I would rather just get it over with and change (and henceforth use) the source with a for-loop (rather than a map built-in: for clarity):
      c:\@Work\Perl\monks>perl -wMstrict -MData::Dumper -le "my @in = ('Maria-s', 'Thano-s'); s/-/+/g for @in; print Dumper \@in; " $VAR1 = [ 'Maria+s', 'Thano+s' ];

      Prior to Perl version 5.14, aliased substitution can be avoided by substitution-on-assignment:

      c:\@Work\Perl\monks>perl -wMstrict -MData::Dumper -le "print 'perl version: ', $]; ;; my @in = ('Maria-s', 'Thano-s'); my @out = map { (my $mp = $_) =~ s/-/+/g; $mp; } @in; print Dumper \@in; print Dumper \@out; " perl version: 5.008009 $VAR1 = [ 'Maria-s', 'Thano-s' ]; $VAR1 = [ 'Maria+s', 'Thano+s' ];
      With version 5.14+, the  /r substitution modifier can be used:
      c:\@Work\Perl\monks>perl -wMstrict -MData::Dumper -le "print 'perl version: ', $]; ;; my @in = ('Maria-s', 'Thano-s'); my @out = map { s/-/+/gr } @in; print Dumper \@in; print Dumper \@out; " perl version: 5.014004 $VAR1 = [ 'Maria-s', 'Thano-s' ]; $VAR1 = [ 'Maria+s', 'Thano+s' ];


      Give a man a fish:  <%-{-{-{-<

        Building on AnomalousMonk's "Prior to Perl version 5.14" example we can come up with this SSCCE:

        use strict; use warnings; use Test::More tests => 3; my $data = {x => "Maria's"}; my $old = \%$data; my @allparms = sort keys %$data; my @oldparms = @allparms; my @expected = ("Maria''s"); my @result = map { (my $f = $data->{$_} || '') =~ s/'/''/g; $f } @allp +arms; is_deeply \@result, \@expected, "apostrophe's are doubled"; is_deeply $data, $old, '$data is unchanged'; is_deeply \@allparms, \@oldparms, '@allparms is unchanged';

        You can then extend $data and @expected to provide a more comprehensive set of test data to prove that the algorithm matches your needs. All of this assumes (contrary to expectation) that choroba's guess that this is actually an XY Problem is incorrect.

        Hi and I hope you can see this again!
        I got it to work, my Perl version is v5.10.1, but I am getting a warning message as this:

        Useless use of a constant in void context at... that's from the line where the call is.

        I am actually replacing MSWord quote with a regular quote since the DB can't handle it, but if I pass a normal single quote using place holders, it works. This how my code looks like now:
        my @allparms = qw( letters loc type name zip); my $sql = exec_select( "call store_proc(" . join(',', ('?') x @allparm +s ) . ")", map { (my $dx = $data->{ $_ }) =~ s/’/'/g || '' ; $dx; } @ +allparms );
        How could a prevent this warning and why is it happening ?
        Thanks for looking!