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

Hi, I have an array containing some user entries which we'd like to load into a database. But the database require us to escape each '\' first. Here is the condition. The number of '\' can vary in each element and the position can be anywhere in the element. I come up with the following piece of code which works if I replace '\' with a random character like '0'. It "duplicates" each 0 with another 0 correctly regardless of how many and where it is. However if I replace it with '\', it failed to make a copy of each backslash. I am not sure what went wrong. Can someone shed some light please?

@row=('aa','bb','\\c\c\','d\d'); $separator=','; foreach (@row) { s/(\\+)/$1$1/g; } print join($separator, @row); print "\n";

------------ Result: aa,bb,\\\\c\\c\\,d\\d

Replies are listed 'Best First'.
Re: escape each backslash of each array element
by ikegami (Patriarch) on Jun 24, 2010 at 06:55 UTC

    Use placeholders!!

    my $sth = $dbh->prepare(" INSERT INTO Table ( foo, bar ) VALUES ( ?, ? ) "); $sth->execute($foo, $bar);

    If you can't, use the escape functions the database driver provides!

    my @fields = keys(%data); my $q_fields = join ', ', map $dbh->quote_identifier($_), @fields; my $q_values = join ', ', map $dbh->quote($_), @data[ @fields ]; my $sth = $dbh->prepare(" INSERT INTO Table ( $q_fields ) VALUES ( $q_values ) "); $sth->execute();

    Better:

    my @fields = keys(%data); my $q_fields = join ', ', map $dbh->quote_identifier($_), @fields; my $pholders = join ', ', ('?') x @fields; my $sth = $dbh->prepare(" INSERT INTO Table ( $q_fields ) VALUES ( $pholders ) "); $sth->execute(@data[ @fields ]);
Re: escape each backslash of each array element
by NetWallah (Canon) on Jun 24, 2010 at 06:05 UTC
    Not the most elegant, but this does the job:
    $_=join qq#\\\\#,split(/\\/,$_,-1);
    As far as shedding light on your code:
    The problem is that the "g" tag, by itself does not repeat replacement.

    You need to put the substitution into a loop until no more substitutions are made.

    The problem with that approach is that (for me) that loops infinitely, as it discovers more "\\" replacing "\".

    I'm sure a wiser monk will provide the appropriate elegant hack.

    Here is another approach, using substitution:

    >perl -e "my @s=qw(\\\\c\\c\\ d\\d aa bb); for my $x(@s){($y=$x)=~ s#( +\\+)#$1$1#g;print qq{$y=$x;\n}}" \\\\c\\c\\=\\c\c\; d\\d=d\d; aa=aa; bb=bb;
    Update:Struck incorrect statements, and improved second sample code.

         Syntactic sugar causes cancer of the semicolon.        --Alan Perlis

Re: escape each backslash of each array element
by dineed (Scribe) on Jun 24, 2010 at 06:53 UTC

    I see a problem with: @row=('aa','bb','\\c\c\','d\d');

    I believe the compiler is reading an odd number of tick marks (') because your example is escaping the tick mark that follows the last c\ combination.

    When I read @row as input (see below), I get the same output you showed for "result". I assumed that was your desired output.

    my @row=(<DATA>); my $separator=','; foreach (@row) { s/(\\+)/$1$1/g; } print join($separator, @row); print "\n"; __DATA__ aa,bb,\\c\c\,d\d
    Output: aa,bb,\\\\c\\c\\,d\\d
Re: escape each backslash of each array element
by colwellj (Monk) on Jun 24, 2010 at 06:56 UTC
    bplegend,
    I assume that you pull the array in from somewhere else rather than as you put it in your code snippet
    That is, when I tried your code above after adding warnings and strict. Perl complained that I was using a bareword because the "\'" after the c is translated as an escaped "'" and not the end of the variable.
    Have you checked for any errors coming up?
    It seems to work fine for me.
    I tried;
    #!/usr/bin/perl -w use strict; my @row; my $separator=','; open(INPUT,"< temp.txt") or die "could not open"; while(<INPUT>){ chomp; push @row,$_;}; foreach (@row) { s/(\\+)/$1$1/g; } print join($separator, @row); print "\n";
    and got aa,bb,\\\\c\\c\\,d\\d
    temp.txt contained
    aa bb \\c\c\ d\d
Re: escape each backslash of each array element
by Khen1950fx (Canon) on Jun 24, 2010 at 06:59 UTC
    Here's my stab at it. If it's not what you need, please let me know.
    #!/usr/bin/perl use strict; use warnings; use Data::Dumper::Concise; my @row = q(aa, bb, \\c\c\, d\d); foreach (@row) { s/(\\+)/$1$1/; } print Dumper(join(',', @row));
Re: escape each backslash of each array element
by johngg (Canon) on Jun 24, 2010 at 12:24 UTC

    Using the database driver escape functions as ikegami suggests is probably the best approach. In general though, trying to deal with backslashes usually makes my brain explode so I tend to utilise the hex representation instead. I find it vastly less confusing.

    $ perl -E ' > @row = ( > q{aa}, > q{bb}, > qq{\x5c\x5cc\x5cc\x5c}, > qq{d\x5cd}, > ); > say qq{@row}; > s{\x5c}{\x5c\x5c}g for @row; > say qq{@row};' aa bb \\c\c\ d\d aa bb \\\\c\\c\\ d\\d $

    I hope this is helpful.

    Cheers,

    JohnGG

Re: escape each backslash of each array element
by bplegend (Novice) on Jun 24, 2010 at 19:33 UTC
    argh.. that is right. I forgot about escaping through the db driver. I will look into whether it works for me. Thank you for other inputs and they all work well for me.