Improvised way to use split function - perl

I am using split function to extract the a string from given line.
exp :
\abc\Logs\PostBootLogs\05-27-2014_17-05-51\UILogs_05-27-2014_17-05-52.txt
\abc\Logs\PostBootLogs\01-10-1970_20-33-22\01-10-1970_21-18-26\UILogs_01-10-1970_21-18-27.txt
In the above exp we need to capture string which is there between PostBootLogs and UILogs_01-10-1970_21-18-27.txt
Code :
use strict;
use warnings;
my $data = '\abc\Logs\PostBootLogs\05-27-2014_17-05-51\UILogs_05-27-2014_17-05-52.txt';
my $test1 = '\abc\Logs\PostBootLogs\01-10-1970_20-33-22\01-10-1970_21-18-26\UILogs_01-10-1970_21-18-27.txt';
my #values = split('UILogs'(split('PostBootLogs', $data)));
my #values1 = split('UILogs', $values[1]);
print "$values1[0]\n\n";
print "$test1\n\n";
my #values_1= split('PostBootLogs', $test1);
my #values1_1 = split('UILogs', $values_1[1]);
print $values1_1[0];
exit 0;
is there any better way to do this thing?

You can use regex to capture between PostBootLogs\ and \UILogs
my ($captured) = $data =~ /PostBootLogs\\ (.+?) \\UILogs/x;

Regular expressions make this sort of thing much easier.
$data =~ m/PostBootLogs(.*?)UILogs/ or die "Misformatted data";
my $timestamps = $1;

Creative use of splits. As has been demonstrated, the easiest method to do this is to use a regex.
However, if you want to see how to use splits to more cleanly accomplish this observe the following:
use strict;
use warnings;
my #data = qw(
\abc\Logs\PostBootLogs\05-27-2014_17-05-51\UILogs_05-27-2014_17-05-52.txt
\abc\Logs\PostBootLogs\01-10-1970_20-33-22\01-10-1970_21-18-26\UILogs_01-10-1970_21-18-27.txt
);
print "splits: \n";
for (#data) {
my ($vol, #path) = split /\\/;
my $subdir = join '\\', #path[3..$#path-1];
print $subdir, "\n";
}
print "regex: \n";
for (#data) {
if (/PostBootLogs\\(.*)\\UILogs/) {
print "$1\n";
} else {
warn "Data format not recognized: $_";
}
}
Outputs:
splits:
05-27-2014_17-05-51
01-10-1970_20-33-22\01-10-1970_21-18-26
regex:
05-27-2014_17-05-51
01-10-1970_20-33-22\01-10-1970_21-18-26

Related

How can I enter and return a single letter properly from a sub in Perl?

I am attempting to write a code that will encrypt letters with a basic cyclic shift cipher while leaving any character that is not a letter alone. I am trying to do this through the use of a sub that finds the new value for each of the letters. When I run the code now,it formats the result so there is a single space between every encrypted letter instead of keeping the original formatting. I also cannot get the result to be only in lowercase letters.
sub encrypter {
my $letter = shift #_;
if ($letter =~ m/^[a-zA-Z]/) {
$letter =~ y/N-ZA-Mn-za-m/A-Za-z/;
return $letter;
}
else {
return lc($letter);
}
}
print "Input string to be encrypted: ";
my $input = <STDIN>;
chomp $input;
print "$input # USER INPUT\n";
my #inputArray = split (//, $input);
my $i = 0;
my #encryptedArray;
for ($i = 0; $i <= $#inputArray; $i++) {
$encryptedArray[$i] = encrypter($inputArray[$i]);
}
print "#encryptedArray # OUTPUT\n";
You might try changing this line:
if ($letter = m/[^a-zA-Z]/ ) {
To something more like this:
if ($letter =~ m/^[a-zA-Z]/) {
In the original line you are doing an assignment to the variable $letter, and the ^ will need to be before the [a-zA-Z] for the comparison.
You're attempting to do a rot13 translation on your characters. This can be done a little easier using tr:
use strict;
use warnings;
sub rot13 {
my $string = shift;
$string =~ tr/a-zA-Z/n-zA-Za-m/;
return $string;
}
print "Input string to be encrypted: ";
chomp(my $input = <STDIN>);
print "$input # USER INPUT\n";
print "Cycle of 4:\n";
for (1..4) {
$input = rot13($input);
print " $input\n";
}
Outputs
Input string to be encrypted: asdf
asdf # USER INPUT
Cycle of 4:
nFqs
ASDF
NfQS
asdf
Here is a some kind of more general implementation of it, it is easier to adapt it to something like, for example, using different rotation places for different letter:
#!/usr/bin/perl
use strict;
use warnings;
use feature qw(switch say);
sub rotateBy {
my ($letter, $rotate_places) = #_;
$rotate_places = $rotate_places ? $rotate_places : 13;
my $width = (ord 'z') - (ord 'a') + 1;
sub rotate {
my ($let, $base, $places, $width) = #_;
my $i = (ord $let) - (ord $base);
return chr((ord $base) + ($i + $places) % $width);
}
given ($letter) {
when (m/[a-z]/) {
return rotate ($letter, 'a', $rotate_places, $width);
}
when (m/A-Z/) {
return rotate ($letter, 'A', $rotate_places, $width);
}
default {
return $letter;
}
}
}
while (<>) {
chomp;
print "PLAINTEXT : $_\n";
print "CIPHERTEXT: ";
foreach my $let (split //) {
print rotateBy($let);
}
print "\n";
}
By the way, the above code looks too verbose to me, maybe there is a better way to do it.

How to search a string in web page and print that full line in which search string is present?

I'm new to programming, learning perl as well.
Here's my question: How do I search a string in web page and print that full line in which search string is present?
Is it possible to find/hit directly that string and then print that full line in which search string is present? Do we need to use xpaths compulsory for this?
If it is just a very basic string you are looking for you can use LWP::Simple and a small regular expression like this:
use LWP::Simple;
my $doc = get('http://stackoverflow.com/q/11771655/479133') || die "GET failed";
foreach my $line (split("\n", $doc)) {
print $line and last if $line =~ m/Here's my query/;
}
There are countless modules available on CPAN to do such things. Have a look at Task::Kensho::WebCrawling if you need something "bigger".
LWP::UserAgent and HTML::Parser can be used:
#!/usr/bin/env perl
use strict;
use warnings;
use HTML::Parser;
use LWP::UserAgent;
my $ua = LWP::UserAgent->new;
my $response = $ua->get('http://search.cpan.org/');
if ( !$response->is_success ) {
print "No matches\n";
exit 1;
}
my $parser = HTML::Parser->new( 'text_h' => [ \&text_handler, 'dtext' ] );
$parser->parse( $response->decoded_content );
sub text_handler {
chomp( my $text = shift );
if ( $text =~ /language/i ) {
print "Matched: $text\n";
}
}

How can match the first value of #ARGV to an array of possible options

I am trying to figure a way to capture the first argument from #ARGV and check its validity by checking it against an array of known valid arguments. I thought I could do this with a simple foreach loop but I realized this won't work because it will fail when the first invalid match comes back, which for my example script is the second argument.
Here the code that pertains to the problem, its concept script so there is not much.
my $primary_mode = $ARGV[0];
primary_mode_check($primary_mode);
sub primary_mode_check {
my #program_modes = ('create', 'destroy');
my $selected_mode = shift;
foreach my $mode (#program_modes) {
if ($selected_mode ne $mode) {
die RED "\'$selected_mode\' is not a valid program mode!\n";
}
}
}
Is there another way to accomplish the same idea? I am already using Getopt::Long in combonation with #ARGV to achieve a certain style. So I am focused on wanting to make this work.
UPDATE
I was thinking maybe I could match against regex, is that a possibility?
my $primary_mode = $ARGV[0] or die "No mode provided";
primary_mode_check($primary_mode);
sub primary_mode_check {
my $selected_mode = shift;
my #program_modes = ('create', 'destroy');
die "'$selected_mode' is not a valid program mode!\n"
unless grep { $selected_mode eq $_ } #program_modes;
}
If you are using perl 5.10 or greater:
use v5.10;
my $primary_mode = $ARGV[0] or die "No mode provided";
my #program_modes = qw(create destroy);
die "'$selected_mode' is not a valid program mode!\n"
unless $primary_mode ~~ #program_modes;
You code: Die if the arg doesn't match one of the allowed modes.
You want: Die if the arg doesn't match any of the allowed modes.
Put differently: Don't die if the arg matches one of the allowed modes.
my #program_modes = qw( create destroy );
sub primary_mode_check {
my ($selected_mode) = #_;
for my $mode (#program_modes) {
return if $selected_mode eq $mode;
}
die "'$selected_mode' is not a valid program mode!\n";
}
But a hash simplifies things a bit.
my %program_modes = map { $_ => 1 } qw( create destroy );
sub primary_mode_check {
my ($selected_mode) = #_;
die "'$selected_mode' is not a valid program mode!\n"
if !$program_modes{$selected_mode};
}
You might find App::Cmd useful for easy writing of application with commands.
I would recommend going with a hash of allowed modes. In addition, pass the allowed modes to the function rather than embedding them in the function.
You can also use grep for this purpose if the allowed modes are in an array:
#!/usr/bin/env perl
use warnings; use strict;
my ($primary_mode) = #ARGV;
my $allowed_modes = [qw(create destroy)];
check_primary_mode($primary_mode, $allowed_modes)
or die sprintf "%s is not a valid program mode\n", $primary_mode;
sub check_primary_mode {
my ($mode, $allowed) = #_;
return grep $mode eq $_, #$allowed;
}
However, grep will go through the entire array even though we need just one match. List::MoreUtils::first_index will short-circuit once a match is found (it does not matter if you have only two possible modes, but in the more general case, it might):
use List::MoreUtils qw( first_index );
...
sub check_primary_mode {
my ($mode, $allowed) = #_;
return (0 <= first_index { $mode eq $_ } #$allowed);
}
my $primary_mode = $ARGV[0];
primary_mode_check($primary_mode);
sub primary_mode_check {
my %program_modes; #program_modes{qw(create destroy)}=();
my $selected_mode = shift;
die RED "\'$selected_mode\' is not a valid program mode!\n"
unless exists $program_modes{$selected_mode};
}
I often use this idiom in such a case:
use strict;
use warnings;
my $cmd = shift #ARGV;
my #allowed = qw/ install uninstall check purge /;
die "Cannot understand command" unless ( grep { $cmd eq $_ } #allowed );
Edit: reading more carefully it looks quite a bit like Sinan's, and he's right, using first would search faster in a large list of possible ops.
Yes, a regular expression should work. For example:
my #modes = ('create', 'destroy');
my $regexp = join "|", #modes;
if ($selected =~ /^(?:$regexp)\z/) {
print "Found program mode '$1'\n";
} else {
die RED "\'$selected\' is not a valid program mode!\n";
}

What module can I use to parse RSS feeds in a Perl CGI script?

I am trying to find a RSS parser that can be used with a Perl CGI script. I found simplepie and that's really easy parser to use in PHP scripting. Unfortunately that doesn't work with a Perl CGI script. Please let me know if there is anything that's easy to use like simplepie.
I came across this one RssDisplay but I am not sure about the usage and also how good it is.
From CPAN: XML::RSS::Parser.
XML::RSS::Parser is a lightweight liberal parser of RSS feeds. This parser is "liberal" in that it does not demand compliance of a specific RSS version and will attempt to gracefully handle tags it does not expect or understand. The parser's only requirements is that the file is well-formed XML and remotely resembles RSS.
#!/usr/bin/perl
use strict; use warnings;
use XML::RSS::Parser;
use FileHandle;
my $parser = XML::RSS::Parser->new;
unless ( -e 'uploads.rdf' ) {
require LWP::Simple;
LWP::Simple::getstore(
'http://search.cpan.org/uploads.rdf',
'uploads.rdf',
);
}
my $fh = FileHandle->new('uploads.rdf');
my $feed = $parser->parse_file($fh);
print $feed->query('/channel/title')->text_content, "\n";
my $count = $feed->item_count;
print "# of Items: $count\n";
foreach my $i ( $feed->query('//item') ) {
print $i->query('title')->text_content, "\n";
}
Available Perl Modules
XML::RSS::Tools
XML::RSS::Parser:
#!/usr/bin/perl -w
use strict;
use XML::RSS::Parser;
use FileHandle;
my $p = XML::RSS::Parser->new;
my $fh = FileHandle->new('/path/to/some/rss/file');
my $feed = $p->parse_file($fh);
# output some values
my $feed_title = $feed->query('/channel/title');
print $feed_title->text_content;
my $count = $feed->item_count;
print " ($count)\n";
foreach my $i ( $feed->query('//item') ) {
my $node = $i->query('title');
print ' '.$node->text_content;
print "\n";
}
XML::RSS::Parser::Lite (Pure Perl):
use XML::RSS::Parser::Lite;
use LWP::Simple;
my $xml = get("http://url.to.rss");
my $rp = new XML::RSS::Parser::Lite;
$rp->parse($xml);
print join(' ', $rp->get('title'), $rp->get('url'), $rp->get('description')), "\n";
for (my $i = 0; $i < $rp->count(); $i++) {
my $it = $rp->get($i);
print join(' ', $it->get('title'), $it->get('url'), $it->get('description')), "\n";
}
dirtyRSS:
use dirtyRSS;
$tree = parse($in);
die("$tree\n") unless (ref $tree);
disptree($tree, 0);

What is a good way to read in text?

In my sms-script I read in the text to send with this subroutine:
my $input = input( "Enter the input: " );
sub input {
my $arg = shift;
print $arg if $arg;
print "\n ";
chomp( my $in = <> );
return $in;
}
This way I can correct errors only through canceling all until I reach the error and this only in the last line.
Is there a better way to read in my text?
This is the "normal" way to read input:
use strict;
use warnings;
# ...
while (my $input = <>)
{
chomp $input;
handle_error($input), next unless validate($input);
# do something else with $input...
}
You can use a while loop inside your input subroutine, e.g.
my $is_valid = 0;
my $input;
while (!$is_valid) {
print "Enter something: ";
$input = <>;
$is_valid = validate_input($input);
}