shuffle url parameter behind & in Perl - perl

Hello i was wondering if anyone know how to shuffle an url with perl, but then only all parameters after the &.
here's an example:
anyurl=i&ct=1&cad=1&rsm=6&ei=JthyULClH8fH0QWcooD4Bw&zx=1349703728841
here's what im looking for:
anyurl=i&ei=JthyULClH8fH0QWcooD4Bw&cad=1&ct=1&rsm=6&zx=1349703728841
just so that all parameters behind the & are placed on a different place randomly. So i want all parameters behind the & on a different place every print, is this possible?
thnx in advance.

#!/usr/bin/env perl
use strict;
use warnings;
use List::Util qw(shuffle);
my $url = 'http://www.anyurl.com/userdata?ct=1&cad=1&rsm=6&ei=JthyULClH8fH0QWcooD4Bw&zx=1349703728841';
my #parts = split(/\?/,$url);
my $parms = join('&',shuffle(split(/&/,$parts[1])));
my $shuffled = join('?',$parts[0],$parms);
print $shuffled;
can be shorter, but this is a step-by-step idea of how to do that.

Try converting the query string into an array and then shuffling the array:
my $qryStr = 'ct=1&cad=1&rsm=6&ei=JthyULClH8fH0QWcooD4Bw&zx=1349703728841';
my #init = split('&', $qryStr);
my $i = #init;
my #shfld;
while($i--)
{
my $j = int(rand($i+1));
$shfld[$i] = $init[$j];
splice(#init, $j, 1);
}
my $rslt = join('&', #shfld);
print "\nRESULT = ".$rslt;

Related

What is this perl object and how do I iterate through it?

I have a perl object that was returned to me whose data I can't seem to extract. If I run Data::Dumper->Dump on it as:
Data::Dumper->Dump($message_body)
I get:
$VAR1 = 'SBM Message
';
$VAR2 = '--SBD.Boundary.605592468
';
$VAR3 = 'Content-Type: text/plain;charset=US-ASCII
';
$VAR4 = 'Content-Disposition: inline
If I execute the line:
print $message_body;
I get:
ARRAY(0x9145668)
I would think this is an array. However, trying to iterate through it there only seems to be a single element. How do I extract each of the elements from this? By the way this, is basically the body of a mail message extracted using the MIME::Parser package. It was created using the following:
my $parser = new MIME::Parser;
my $entity = $parser->parse($in_fh); # Where $in_fh points to a mail message
$message_body = $entity->body;
Try below foreach loop.
foreach my $item (#{$message_body})
{
print $item."\n";
}
$message_body is an ARRAY reference. Hence you need to dereference it and then iterate through each element using the foreach loop.
Read:
http://perlmeme.org/howtos/using_perl/dereferencing.html and http://www.thegeekstuff.com/2010/06/perl-array-reference-examples/
Data::Dumper is only a poor man's choice to see the content.
To see all the gory internal details use Devel::Peek instead.
use Devel::Peek;
Dump $message_body;

Randomizing a list using Rand in perl

Hi i currently am using the List::Util shuffle to randomize a array with CGI however I want to modify the code to use rand instead
here is my code
print "Content-type: text/html\n\n";
use List::Util qw(shuffle);
#haikuone = ('behind', 'the', 'red', 'barn');
#haikutwo = ('prairie', 'grasses', 'reclaiming');
#haikuthree = ('the', 'basketball', 'court');
#randomize1 = shuffle(#haikuone);
#randomize2 = shuffle(#haikutwo);
#randomize3 = shuffle(#haikuthree);
print "<html>\n";
print "<head><title>Haiku_Random</title></head>\n";
print "<body>\n";
print "<pre>\n";
print "RANDOM HAIKU (DISCLAIMER: NONSENSE MAY OCCUR)\n";
print "#randomize1\n";
print "#randomize2\n";
print "#randomize3\n";
How would i modify this code to use rand instead of List::Util
I dont think its much but a novice here
I'm trying to get this working
$haikuone = ('behind', 'the', 'red', 'barn');
$haikutwo = ('prairie', 'grasses', 'reclaiming');
$haikuthree = ('the', 'basketball', 'court');
#random1 = $line1[rand #haikuone];
#random2 = $line2[rand #haikutwo];
#random3 = $line3[rand #haikuthree];
print "RANDOM HAIKU (DISCLAIMER: NONSENSE MAY OCCUR)\n";
print "$line1\n";
Now when i do this
#!/usr/local/bin/perl
#haikuone = ('behind', 'the', 'red', 'barn');
#haikutwo = ('prairie', 'grasses', 'reclaiming');
#haikuthree = ('the', 'basketball', 'court');
#random1 = $line1[rand #haikuone];
#random2 = $line2[rand #haikutwo];
#random3 = $line3[rand #haikuthree];
print "RANDOM HAIKU (DISCLAIMER: NONSENSE MAY OCCUR)\n";
print "#haikuone\n";
It will print haikuone but it wont randomize it
sub fisher_yates_shuffle {
my $deck = shift; # $deck is a reference to an array
return unless #$deck; # must not be empty!
my $i = #$deck;
while (--$i) {
my $j = int rand ($i+1);
#$deck[$i,$j] = #$deck[$j,$i];
}
}
my #randomize1 = #haikuone;
fisher_yates_shuffle(\#randomize1);
print "#randomize1\n";
Always use use strict; use warnings;! You have the following code, but don't have any arrays named #haikuone, #haikutwo, #haikuthree, #line1, #line2 or #line3.
#random1 = $line1[rand #haikuone];
#random2 = $line2[rand #haikutwo];
#random3 = $line3[rand #haikuthree];
It's also really weird that use three arrays with one element each.
Hi i currently am using the List::Util shuffle to randomize a array
with CGI
This makes sense. List::Util::shuffle() is the best way to shuffle a list in Perl - whether or not you're writing a CGI program.
however I want to modify the code to use rand instead
This doesn't make sense. rand() doesn't shuffle a list. It just generates a random number.
It's a good idea to use rand() to extract a single random element from an array.
my $random_element = #array[rand #array];
But that's not what you're trying to do.
If you really want to use rand() then you need to incorporate its use in a function. There's a good function given in the Perl FAQ (in the answer to the question - "How do I shuffle an array randomly?" - so perhaps you should have taken a look at the FAQ before asking here) which looks like this:
sub fisher_yates_shuffle {
my $deck = shift; # $deck is a reference to an array
return unless #$deck; # must not be empty!
my $i = #$deck;
while (--$i) {
my $j = int rand ($i+1);
#$deck[$i,$j] = #$deck[$j,$i];
}
}
But note that this is implemented in Perl. The shuffle() function in List::Util is written in C, so it's going to be faster.
So, all in all, there's really no good reason for not using List::Util::shuffle().

Extract zip Files on cmd with progress indicator

I am looking for a program, which is able to extract zip archives via the windows commandline and that is able to display a progressbar or a percentage indicator on the cmd. I want to use this from within a Perl script and so give the user a hint how long the progress will take. I tried 7zip(http://www.7-zip.org/) and Unzip(from InfoZIP) so far, but was not able to produce the behaviour described above. Does somebody know how to solve this?
Update:
Currently i'm trying it with this approach:
#!/usr/bin/perl
use strict; $|++;
use warnings;
use Archive::Zip;
my $zip = Archive::Zip->new('file.zip');
my $total_bytes = 0;
my $bytes_already_unzipped = 0;
foreach my $member ($zip->members()) {
$total_bytes += $member->uncompressedSize();
}
foreach my $member ($zip->members()) {
$zip->extractMember($member);
$bytes_already_unzipped += $member->uncompressedSize();
print progress_bar($bytes_already_unzipped, $total_bytes, 25, '=' );
}
#routine by tachyon at http://tachyon.perlmonk.org/
#also have a look at http://oreilly.com/pub/h/943
sub progress_bar {
my ( $got, $total, $width, $char ) = #_;
$width ||= 25; $char ||= '=';
my $num_width = length $total;
sprintf "|%-${width}s| Got %${num_width}s bytes of %s (%.2f%%)\r",
$char x (($width-1)*$got/$total). '>',
$got, $total, 100*$got/+$total;
}
However i have two problems:
this approach seems to be very slow
i do not have a periodic update in the progress bar, but only when a file is finished beeing extracted. As i have some large files, the system seems to not respond while extracting them
Do the extraction from within your program instead of delegating to a different one. Use Archive::Zip and Term::ProgressBar. Extract files one by one. Update the progress after each.

replace variable value and store it in new variable

I have below code to replace the variable value and store it in new variable and leave the original variable intact.
#!/usr/bin/perl
$hdisk="hdisk361";
($newdisk) = ($hdisk =~ s/(hdisk\D*)(\d+)/(($1 eq "hdiskpower"?"prw":"dsk").$2)/ei);
print "hdisk: $hdisk"."\n";
print "newdisk: $newdisk"."\n";
It gives this output:
hdisk: dsk361
newdisk: 1
I want the output like this:
hdisk: hdisk361
newdisk: dsk361
Please help me to fix this code?
Or a bit shorter:
#!/usr/bin/perl
$hdisk="hdisk361";
($newdisk = $hdisk) =~ s/(hdisk\D*)(\d+)/(($1 eq "hdiskpower"?"prw":"dsk").$2)/ei;
Otherwise, as you saw, you get 1, meaning a successful operation. In the code you provided you captured the return value instead of the result.
But don't forget to use use strict and use warnings ;)
Use
$hdisk = "hdisk361"
$newdisk = $hdisk;
$newdisk =~ s/(hdisk\D*)(\d+)/(($1 eq "hdiskpower"?"prw":"dsk").$2/
The substitution s/// works by side-effect. Its return value is hardly ever what you want. You especially don't want to use s here, when you seem not to want $hdisk to change.
Capture the pieces of $hdisk with m instead of s.
use strict;
use warnings;
my $hdisk="hdisk361";
my ($word, $number) = $hdisk =~ m/(hdisk\D*)(\d+)/i;
my $newdisk = ($word eq "hdiskpower"?"prw":"dsk").$number;
print "hdisk: $hdisk"."\n";
print "newdisk: $newdisk"."\n";
This answer is a bit superflous, but anyway, if you are using a fairly modern version of Perl (5.13+), you could have the original code working by just adding the r flag:
use 5.013;
($newdisk) = ($hdisk =~ s/(hdisk\D*)(\d+)/(($1 eq "hdiskpower"?"prw":"dsk").$2)/rei);
You could even let go of the parens:
use 5.013;
my $newdisk = $hdisk =~ s/(hdisk\D*)(\d+)/(($1 eq "hdiskpower"?"prw":"dsk").$2)/rei;
You can read more on the /r flag at Use the /r substitution flag to work on a copy.

How can I expand a string like "1..15,16" into a list of numbers?

I have a Perl application that takes from command line an input as:
application --fields 1-6,8
I am required to display the fields as requested by the user on command line.
I thought of substituting '-' with '..' so that I can store them in array e.g.
$str = "1..15,16" ;
#arr2 = ( $str ) ;
#arr = ( 1..15,16 ) ;
print "#arr\n" ;
print "#arr2\n" ;
The problem here is that #arr works fine ( as it should ) but in #arr2 the entire string is not expanded as array elements.
I have tried using escape sequences but no luck.
Can it be done this way?
If this is user input, don't use string eval on it if you have any security concerns at all.
Try using Number::Range instead:
use Number::Range;
$str = "1..15,16" ;
#arr2 = Number::Range->new( $str )->range;
print for #arr2;
To avoid dying on an invalid range, do:
eval { #arr2 = Number::Range->new( $str )->range; 1 } or your_error_handling
There's also Set::IntSpan, which uses - instead of ..:
use Set::IntSpan;
$str = "1-15,16";
#arr2 = Set::IntSpan->new( $str )->elements;
but it requires the ranges to be in order and non-overlapping (it was written for use on .newsrc files, if anyone remembers what those are). It also allows infinite ranges (where the string starts -number or ends number-), which the elements method will croak on.
You're thinking of #arr2 = eval($str);
Since you're taking input and evaluating that, you need to be careful.
You should probably #arr2 = eval($str) if ($str =~ m/^[0-9.,]+$/)
P.S. I didn't know about the Number::Range package, but it's awesome. Number::Range ftw.
I had the same problem in dealing with the output of Bit::Vector::to_Enum. I solved it by doing:
$range_string =~ s/\b(\d+)-(\d+)\b/expand_range($1,$2)/eg;
then also in my file:
sub expand_range
{
return join(",",($_[0] .. $_[1]));
}
So "1,3,5-7,9,12-15" turns into "1,3,5,6,7,9,12,13,14,15".
I tried really hard to put that expansion in the 2nd part of the s/// so I wouldn't need that extra function, but I couldn't get it to work. I like this because while Number::Range would work, this way I don't have to pull in another module for something that should be trivial.
#arr2 = ( eval $str ) ;
Works, though of course you have to be very careful with eval().
You could use eval:
$str = "1..15,16" ;
#arr2 = ( eval $str ) ;
#arr = ( 1..15,16 ) ;
print "#arr\n" ;
print "#arr2\n" ;
Although if this is user input, you'll probably want to do some validation on the input string first, to make sure they haven't input anything dodgy.
Use split:
#parts = split(/\,/, $fields);
print $parts[0];
1-6
print $parts[1];
8
You can't just put a string containing ',' in an array, and expect it to turn to elements (except if you use some Perl black magic, but we won't go into that here)
But Regex and split are your friends.