Dave, that's the way I would have done if given enough time.
Mirco, you're way over my head. I tested your code and indeed "The
sneaky cat sneaked angrily". But after reading japhy's "Regex
Arcana" (
http://japhy.perlmonk.org/articles/tpj/2004-summer.html) for
a few minutes I realized that, being "only an electrical engineer", my
Business Manager would not appreciate the amount of time it would take
me to get up to speed on these amazing "code assertions" and "atomic
groups". But thank you very much for those references. A Google
search for "(??{...})" would not have been very fruitful. If I ever
need these things I've got a bookmark.
Gunnar's solution I was able to understand and modify to do what I
really wanted to do, which is, in DBI database queries, to replace "
= ? " with "IS NULL" when placeholders are undef. This problem is
described in
http://search.cpan.org/~timb/DBI-1.605/DBI.pm#Placeholders_and_Bind_Values,
in the subsection "Null Values", but that document doesn't give a
function to test the whole values array and query after construction,
which I could call at a low level in my code to avoid having to
remember to do this all the time. I now have such a function,
explicifyNullsInRefs, shown below.
Thanks for the help!
P.S. There are probably still bugs in this code. Also, probably
someone will point me at a function in a CPAN module that already does
this. Oh, well.
#!/usr/bin/perl
# Problem: A query to find names of all small,
# healthy, 3-year old, albino, fast pets
# Demo Code
my $query = q{SELECT name FROM pets
WHERE
size = ? AND disease = ? AND 'age' = ? and `color`=? and
speed>?} ;
my @values = ("small", undef, 3, undef, 66) ;
print "Query and Values before explifying NULLs:\n" ;
print $query, "\n" ;
printArrayRef(\@values) ;
explicifyNullsInRefs(\$query, \@values) ;
print "\n" ;
print "Query and Values after explifying NULLs:\n" ;
print $query, "\n" ;
printArrayRef(\@values) ;
# Reuseable function
sub explicifyNullsInRefs {
my $queryRef = shift ;
my $valuesRef = shift ;
my $n = " IS NULL" ;
my $e = " = " ;
my $q = "?" ;
my @prunedValues ;
my $i ;
my $k ; # to offset future replacements by current replacment
for my $value (@$valuesRef) {
if (!defined($value)) {
my $j = 0 ;
$$queryRef =~ s/([`'"\w]+)([\s]*)=([\s]*)\?/$j++==$i-$k?
$1.$n:$1.$e.$q/eg ;
$k++ ;
}
else {
push(@prunedValues, $value) ;
}
$i++ ;
}
@$valuesRef = @prunedValues
}
# Function used in demo
sub printArrayRef {
my $aRef = shift ;
my $nA = @$aRef ;
print "$nA values: (" ;
my $i ;
foreach my $v (@$aRef) {
my $printValue = defined($v) ? $v : "<undef>" ;
print $printValue ;
if ($i++ < $nA-1) {
print ", " ;
}
}
print ")\n" ;
}