Can somebody help me with this error of mine? Im using sagepay module on my oscommerce website and i got this error: Warning: Division by zero in sage_pay_form.php on line 406. Here's the code.
function simpleXor($InString, $Key) {
$KeyList = array();
$output = "";
for ($i=0; $i<strlen($Key); $i++) {
$KeyList[$i] = ord(substr($Key, $i, 1));
}
for ($i=0; $i<strlen($InString); $i++) {
$output .= chr(ord(substr($InString, $i, 1)) ^ ($KeyList[$i % strlen($Key)]));
}
whats wrong with this?
$output .= chr(ord(substr($InString, $i, 1)) ^ ($KeyList[$i % strlen($Key)]));
If that percent sign is the modulus operator, then the answer is obvious: strlen($key) must be zero.
Just in case you don't know, modulus is the operator that says "if z = x % y, then z equals the remainder that's left over when you divide x by y." So
z = x % y equals 1 if x = 5 and y = 2.
There's a division going on.
So if your $key is an empty string it'll have zero length. If it has zero length, you'll divide by zero to get the modulus. See the problem? You're assuming that string can never be empty, but your code found a case where it is. Check your assumptions.
Related
I have a list of strings which denote time values, i.e. 1us, 100ps, 10s, 7fs (microseconds, picoseconds, seconds, femtoseconds, etc).
I need to sort the list in ascending order. To do that, I wrote a comparison routine which when given two strings, translates each string into the corresponding numerical value and compares them. Still, the list is not sorted correctly. After much debugging, I'm at a loss. Here's my code:
#!/usr/bin/perl
use warnings;
use strict;
my %scales = ('fs'=>1e-15,'ps'=>1e-12,'ns'=>1e-9,'us'=>1e-6,'ms'=>1e-3,'s'=>1);
my #times = ('1s','7ns','100ps','500ms','9us');
my #stimes = sort bytime #times;
sub bytime {
my $op1 = $a;
my $op2 = $b;
$op1 =~ /\b(\d+)([munpf]*s)\b/;
my $v1 = $1 * $scales{$2};
$op2 =~ /\b(\d+)([munpf]*s)\b/;
my $v2 = $1 * $scales{$2};
return $v1 > $v2;
}
print "#times"."\n"."#stimes"."\n";
The result I get is:
1s 7ns 100ps 500ms 9us
100ps 7ns 500ms 1s 9us
which is clearly wrong, even though some sorting takes place.
What's going on?
Your error is on the line
return $v1 > $v2;
It will return 1 (true) if $v1 is greater than $v2 and 0 (false) in all other cases.
You want to instead use the numerical comparison operator <=>:
return $v1 <=> $v2;
which will return 1, 0 or -1 depending on the comparison result and will allow the sort to do its work correctly. (If you were dealing with strings instead of numbers, the operator would be cmp.)
Complete working code:
#!/usr/bin/perl
use warnings;
use strict;
my %scales = ('fs'=>1e-15,'ps'=>1e-12,'ns'=>1e-9,'us'=>1e-6,'ms'=>1e-3,'s'=>1);
my #times = ('1s','7ns','100ps','500ms','9us');
my #stimes = sort bytime #times;
sub bytime {
my $op1 = $a;
my $op2 = $b;
$op1 =~ /\b(\d+)([munpf]*s)\b/;
my $v1 = $1 * $scales{$2};
$op2 =~ /\b(\d+)([munpf]*s)\b/;
my $v2 = $1 * $scales{$2};
return $v1 <=> $v2;
}
print "#times"."\n"."#stimes"."\n";
Output:
1s 7ns 100ps 500ms 9us
100ps 7ns 9us 500ms 1s
i need to implement a program to count the occurrence of a substring in a string in perl. i have implemented it as follows
sub countnmstr
{
$count =0;
$count++ while $_[0] =~ /$_[1]/g;
return $count;
}
$count = countnmstr("aaa","aa");
print "$count\n";
now this is what i would normally do. however, in the implementation above i want to count occurrence of 'aa' in 'aaa'. here i get answer as 1 which seems reasonable but i need to consider the overlapping cases as well. hence the above case should give an answer as 2 since there are two 'aa's if we consider overlap.
can anyone suggest how to implement such a function??
Everyone is getting pretty complicated in their answers (d'oh! daotoad should have made his comment an answer!), perhaps because they are afraid of the goatse operator. I didn't name it, that's just what people call it. It uses the trick that the result of a list assignment is the number of elements in the righthand list.
The Perl idiom for counting matches is then:
my $count = () = $_[0] =~ /($pattern)/g;
The goatse part is the = () =, which is an empty list in the middle of two assignments. The lefthand part of the goatse gets the count from the righthand side of the goatse. Note the you need a capture in the pattern because that's the list the match operator will return in list context.
Now, the next trick in your case is that you really want a positive lookbehind (or lookahead maybe). The lookarounds don't consume characters, so you don't need to keep track of the position:
my $count = () = 'aaa' =~ /((?<=a)a)/g;
Your aaa is just an example. If you have a variable-width pattern, you have to use a lookahead. Lookbehinds in Perl have to be fixed width.
See ysth's answer ... I failed to realize that the pattern could consist solely of a zero width assertion and still work for this purpose.
You can use positive lookahead as suggested by others, and write the function as:
sub countnmstr {
my ($haystack, $needle) = #_;
my ($first, $rest) = $needle =~ /^(.)(.*)$/;
return scalar (() = $haystack =~ /(\Q$first\E(?=\Q$rest\E))/g);
}
You can also use pos to adjust where the next search picks up from:
#!/usr/bin/perl
use strict; use warnings;
sub countnmstr {
my ($haystack, $needle) = #_;
my $adj = length($needle) - 1;
die "Search string cannot be empty!" if $adj < 0;
my $count = 0;
while ( $haystack =~ /\Q$needle/g ) {
pos $haystack -= $adj;
$count += 1;
}
return $count;
}
print countnmstr("aaa","aa"), "\n";
Output:
C:\Temp> t
2
sub countnmstr
{
my ($string, $substr) = #_;
return scalar( () = $string =~ /(?=\Q$substr\E)/g );
}
$count = countnmstr("aaa","aa");
print "$count\n";
A few points:
//g in list context matches as many times as possible.
\Q...\E is used to auto-escape any meta characters, so that you are doing a substring count, not a subpattern count.
Using a lookahead (?= ... ) causes each match to not "consume" any of the string, allowing the following match to be attempted at the very next character.
This uses the same feature where a list assignment (in this case, to an empty list) in scalar context returns the count of elements on the right of the list assignment as the goatse/flying-lentil/spread-eagle/whatever operator, but uses scalar() instead of a scalar assignment to provide the scalar context.
$_[0] is not used directly, but instead copied to a lexical; a naive use of $_[0] in place of $string would cause the //g to start partway through the string instead of at the beginning if the passed string had a stored pos().
Update: s///g is faster, though not as fast as using index:
sub countnmstr
{
my ($string, $substr) = #_;
return scalar( $string =~ s/(?=\Q$substr\E)//g );
}
You could use a lookahead assertion in the regular expression:
sub countnmstr {
my #matches = $_[0] =~ /(?=($_[1]))/g;
return scalar #matches;
}
I suspect Sinan's suggestion will be quicker though.
you can try this, no more regex than needed.
$haystack="aaaaabbbcc";
$needle = "aa";
while ( 1 ){
$ind = index($haystack,$needle);
if ( $ind == -1 ) {last};
$haystack = substr($haystack,$ind+1);
$count++;
}
print "Total count: $count\n";
output
$ ./perl.pl
Total count: 4
If speed is an issue, the index approach suggested by ghostdog74 (with cjm's improvement) is likely to be considerably faster than the regex solutions.
use strict;
use warnings;
sub countnmstr_regex {
my ($haystack, $needle) = #_;
return scalar( () = $haystack =~ /(?=\Q$needle\E)/g );
}
sub countnmstr_index {
my ($haystack, $needle) = #_;
my $i = 0;
my $tally = 0;
while (1){
$i = index($haystack, $needle, $i);
last if $i == -1;
$tally ++;
$i ++;
}
return $tally;
}
use Benchmark qw(cmpthese);
my $size = 1;
my $h = 'aaa aaaaaa' x $size;
my $n = 'aa';
cmpthese( -2, {
countnmstr_regex => sub { countnmstr_regex($h, $n) },
countnmstr_index => sub { countnmstr_index($h, $n) },
} );
__END__
# Benchmarks run on Windows.
# Result using a small haystack ($size = 1).
Rate countnmstr_regex countnmstr_index
countnmstr_regex 93701/s -- -66%
countnmstr_index 271893/s 190% --
# Result using a large haystack ($size = 100).
Rate countnmstr_regex countnmstr_index
countnmstr_regex 929/s -- -81%
countnmstr_index 4960/s 434% --
I have this regex (which almost work):
s/(?<!\+|-| )(\+|-)(?!=|\+|-| )/ $1 /g;
https://regex101.com/r/oQ8qU8/2
And I want to add a space before and after each + and - char. Here's the test string:
cab+=1+2+3+deb++-5+-5;
The output should be:
cab += 1 + 2 + 3 + deb++ - 5 + -5;
I would like to treat all the C/C++ special cases such as a negative number A=-C->A = -C, an pre/post incremented variable A++=3 -> A++ = 3...
Is there a good solution to use a regexp here?
I wrote a sub for you, since those regular expressions kept growing and growing...
sub format{
my $text = shift;
#substitute '+'
$text =~ s/(?<!\+)\+(?!\+|=)/ \+ /g;
#substitute '-'
$text =~ s/(?<!-)-(?!-|=|>)/ - /g;
#substitute '= , +=, -= (...)'
$text =~ s/([\+,-,\*,\/]?=)/ $1 /g;
#get rid of additional spaces:
$text =~ s/ / /g;
return $text;
}
Here are some results:
converting: foo+--bar++-3 += 3-x--+bar = ++c-*const->char++ +2
to: foo + --bar++ - 3 += 3 - x-- + bar = ++c - *const->char++ + 2
converting: ++x->(a+b+--c) *= c++-++b/=9;
to: ++x->(a + b + --c) *= c++ - ++b /= 9;
converting: b+c+a+d-=++*char->(--c+d);
to: b + c + a + d- = ++*char->(--c + d);
I am posting this for the 1st time. I have gone through similar issues in the forum, but still I am not able to determine why I am getting this error.
Here is a sample code which I am trying to make..
use strict;
use warnings;
my ($m, $b) = #ARGV;
my $count_args = $#ARGV + 1;
my $times = 2**$m;
main();
sub main {
if ( $m =~ /^\d+$/ ) {
if ( $b =~ /^and$/i ) {
func_and();
} else {
print " not supported\n";
}
} else {
print " enter valid number of pins\n";
}
}
sub func_and {
my $bit;
for ( my $i = 0 ; $i < $times ; $i++ ) {
my $p = sprintf( "%0${m}b", $i );
print "$p\t";
my #c = split( '', $p );
my $result = 3;
foreach $bit (#c) {
if ( $result < 3 ) {
$result = $result && $bit;
} else {
$result = $bit;
}
}
print "result for AND operation on $bit is $result \n";
}
}
if i give the input as perl AND.pl 2 and
The error I get is Use of uninitialized value in concatenation (.) or string at NAND.pl line 34.
is there any other way to declare the $ bit variable? and how can one initialize this?
Thanks
Change:
print "result for AND operation on $bit is $result \n";
to:
print "result for AND operation on $p is $result \n";
Then, you can localize $bit to the foreach loop:
foreach my $bit (#c) {
perldoc perlsyn:
The foreach loop iterates over a normal list value and sets the
variable VAR to be each element of the list in turn. If the variable
is preceded with the keyword my, then it is lexically scoped, and is
therefore visible only within the loop. Otherwise, the variable is
implicitly local to the loop and regains its former value upon exiting
the loop.
If the variable was previously declared with my, it uses that variable
instead of the global one, but it's still localized to the loop.
$bit was uninitialized before the loop, so it is still unchanged after the loop.
The worst solution to this problem is to assign a value to $bit when you declare it.
my $bit = 0; # no!!!
While this gets around the error message it makes it difficult to find the logical error in your code. The warning message "use of uninitialized value..." is one of the most important debugging tools you have. If your code produces many such messages, you should turn your warnings into errors so the program halts at the first warning.
use warnings 'FATAL' => 'all';
I am trying to run a script on a .csv file that converts sizes in feet and inches to separate columns of width in inches and height in inches.
It works fine when not using strict mode, but returns a warning message when use warnings; is set.
My problem occurs here:
if ($data[$index_num] =~ /(\d+)'( (\d+)'')? x (\d+)'( (\d+)'')?/) {
my $width = $1*12+$3;
my $height = $4*12+$6;
...
}
Since sometimes the size could be 5' x 8' the special variables $3 and $6 do not exist.
All possible size formats are as follows:
5' 1'' x 6' 7'' (All Single Digits)
10' 1'' x 5' 10'' (Combination of Single and Double Digits)
5' x 8' (No Inches)
4' 6'' x 7' (Combination of No Inches and Inches)
The warning I receive is:
Use of uninitialized value $6 in addition (+) at script.pl line 47, line 567.
This is happening in either case 3 or 4 where the inches are missing on either the width or height.
How can I check to see if either $3 or $6 exists before trying to use them?
You can use defined function:
my $height;
if(defined($6))
{
$height = $4*12+$6;
}
else
{
$height = $4*12;
}
First, let's get rid of useless captures:
/(\d+)'(?: (\d+)'')? x (\d+)'(?: (\d+)'')?/
Captures that didn't match are set to undef, so you can used defined or //.
my $width = $1 * 12 + ($2 // 0);
my $height = $3 * 12 + ($4 // 0);
// was introduced in Perl 5.10. For backwards compatibility, you can use the following:
my $width = $1 * 12 + ($2 || 0);
my $height = $3 * 12 + ($4 || 0);
The second version uses zero when $2 (or $4) is false (undef, zero, or empty string) rather than undef, but that's perfectly fine here.
If you just want to test for a number AND you're happy to calculate a result when there is no match then you could say:
if ($data[$index_num] =~ /(\d+)\'( (\d+)\'\')? x (\d+)\'( (\d+)\'\')?/) {
my $width = ( $1 || 0 ) * 12 + ( $3 || 0 );
my $height = ( $4 || 0 ) * 12 + ( $6 || 0 );
...
}
Why does this work? Because if, say, $1 is undefined, then ($1 || 0) returns the right-hand side, or 0. Likewise if $1 is zero then the left-hand-side of the OR condition will also fail but return 0 nonetheless. And if $1 is non-zero and defined then the left-hand-side will be returned ($1).
If you're going to use the || technique then ensure you put the left-hand and right-hand sides inside parenthesis to avoid operator-precedence side effects.