Perl: Removing characters up to certain point. - string

I've tried searching through questions already asked, but can't seem to find anything. I'm sure its incredibly simple to do, but I am completely new to Perl.
What I am trying to do is remove characters in an string up to a certain point. For example, I have:
Parameter1 : 0xFFFF
and what I would like to do is remove the "Parameter1:" and be left with just the "0xFFFF". If anyone can help and give a simple explanation of the operators used, that'd be great.

Sounds like you need the substr function.
#!/usr/bin/perl
use strict;
use warnings;
my $string = 'Parameter1 : 0xFFFF';
my $fragment = substr $string, 12;
print " string: <$string>\n";
print "fragment: <$fragment>\n";

s/.*:\s*//;
or
$s =~ s/.*:\s*//;
This deletes everything up to and including the first occurrence of : followed by zero or more whitespace characters. With $s =~ it's applied to $s; without it, it's applied to $_.

Have you considered using something like Config::Std?
Here is how to parse a configuration file like that by hand:
#!/usr/bin/perl
use strict; use warnings;
my %params;
while ( my $line = <DATA> ) {
if ($line =~ m{
^
(?<param> Parameter[0-9]+)
\s*? : \s*?
(?<value> 0x[[:xdigit:]]+)
}x ) {
$params{ $+{param} } = $+{value};
}
}
use YAML;
print Dump \%params;
__DATA__
Parameter1 : 0xFFFF
Parameter3 : 0xFAFF
Parameter4 : 0xCAFE
With Config::Std:
#!/usr/bin/perl
use strict; use warnings;
use Config::Std;
my $config = do { local $/; <DATA> };
read_config \$config, my %params;
use YAML;
print Dump \%params;
__DATA__
Parameter1 : 0xFFFF
Parameter3 : 0xFAFF
Parameter4 : 0xCAFE
Of course, in real life, you'd pass a file name to read_config instead of slurping it.

I like split for these parameter/value pairs.
my $str = "Parameter1 : 0xFFFF";
my ($param, $value) = split /\s*:\s*/, $str, 2;
Note the use of LIMIT in the split, which limits the split to two fields (in case of additional colons in the value).

Related

perl match whole word only with array list

I need to be able to match a user to a list of users, but only an exact match.
In the sample code below:
- if strUser contains "info" there is a match and that's good.
- if strUser contains "theinfo", or "infostuff" there is a match and that's not good.
I can't use \b modifiers because the variable will only contain the user name, no spaces or word boundaries.
#!/usr/bin/perl
$strUser = "theinfo";
$strUsers = "(alpha|info|omega)";
if ( $strUser =~ /$strUsers/ ) {
print "match\n";
}
exit(0);
Use a boundaries within your regex ^ and \z:
if ( $strUser =~ /^$strUsers\z/ ) {
Note, since you're likely wanting to work with literal strings, I would put more effort into constructing your regex by using quotemeta:
#!/usr/bin/perl
use strict;
use warnings;
my $strUser = "theinfo";
my #users = qw(alpha info omega);
my $list_users_re = join '|', map {quotemeta} #users;
if ( $strUser =~ /^($list_users_re)\z/ ) {
print "match\n";
}
exit(0);
However, an even easier solution since you're looking for exact matches, is just to use a hash:
my #users = qw(alpha info omega);
my %is_user = map { $_ => 1 } #users;
if ( $is_user{$strUser} ) {
print "match\n";
}
Finally, always include use strict; and use warnings in EVERY perl script.

perl: useing commas in hash values

I have key value pairs as "statement:test,data" where 'test,data' is the value for hash. While trying to create a hash with such values, perl splits the values on the comma. Is there a way around this where strings with commas can be used as values
There is nothing in Perl that stops you from using 'test,data' as hash value.
If your incoming string is literally "statement:test,data", you can use this code to add into hash:
my ($key, $value) = ($string =~ /(\w+):(.*)/);
next unless $key and $value; # skip bad stuff - up to you
$hash{$key} = $value;
Perl won't split a string on a comma unless you tell it to.
#!/usr/bin/perl
use v5.16;
use warnings;
use Data::Dump 'ddx';
my $data = "statement:test,data";
my %hash;
my ($key, $value) = split(":", $data);
$hash{$key} = $value;
ddx \%hash;
gives:
# split.pl:14: { statement => "test,data" }

Remove Part of String Perl

I have this in perl
return "$file->{srv_cgi_url}/dl.cgi/$hash/$fname";
where
$file->{srv_cgi_url}
returns
http://s1.site.com/cgi-bin/
how can I remove the trailing /cgi-bin/ from the string? :)
Thanks!
Like this:
my $new = $file->{srv_cgi_url};
$new =~ s{/cgi-bin/}{};
That is all. See perldoc perlre for details.
While substitution can work, it’s fragile and difficult to extend and maintain. I strenuously recommend learng to use URI, URI::QueryParam, and Path::Class instead (the last is not used in this example but important and related).
use warnings;
use strict;
use URI;
my $file;
$file->{srv_cgi_url} = "http://s1.site.com/cgi-bin/";
my $srv_cgi_uri = URI->new( $file->{srv_cgi_url} );
my $hash = "some";
my $fname = "path.ext";
$srv_cgi_uri->path("/dl.cgi/$hash/$fname");
print $srv_cgi_uri, "\n";
__END__
http://s1.site.com/dl.cgi/some/path.ext

perl code behaving strange

I have written a code to get the url of a website and then search for a string and then compare that string(actually a number) with a hardcoded number
#!/usr/bin/perl
use LWP::Simple;
my $oldversion =36;
$pageURL="http://www.google.com/isos/preFCS5.3/LATESTGOODCVP/";
my $simplePage=get($pageURL);
my $newPage = "$simplePage";
my $str = (split("href=\"CVP-LATEST-5.3.0.",$newPage ))[1];
my $version = substr("$str",0,2);
print $version; // HERE IT PRINT 37 WHICH IS CORRECT
if($version =! $oldVersion )
{
print $version; // BUT HERE IT PRINTS 1 WHICH IS WRONG. HOW IS IT CHANGING ?
##-- fetch the zip and save it as perlhowto.zip
my $status = getstore("http://www.google.com/isos/preFCS5.3/LATESTGOODCVP/CVP-LATEST-5.3.0.$version.iso", "CVP-LATEST-5.3.0.$version.iso");
}
else
{
print("Currently new version\n");
}
Why is it changing the value ? its not able to download the file becuase of that.
You mean !=, not =!, which is an assignment of a negation.
Also, split always uses a regex (except for the very special case of a string that has a single space), so those .s in 5.3.0. will match any non-newline. You probably want to \-escape them.
You may be interested in the uscan script in the debian devtools package.
You have got your "not equals" operator backwards. It should be != rather than =!.
By using =! you are in effect saying "set $version to the negated value of $oldversion".
Here is the offending line
if($version =! $oldVersion ) # Should be if($version != $oldVersion )
Also notice that by using the != operator you are telling perl that $version and $oldversion contain numbers. For string comparisons you should use the ne operator, which assumes that these variables contain strings.
if($version ne $oldVersion ) # String inequality
Here is the documentation for equality operators -
http://perldoc.perl.org/perlop.html#Equality-Operators
It's because you are assigning to $version the value !$oldVersion in this "test":
if($version =! $oldVersion )
And $oldVersion is nothing--but $oldversion is 37. You are assigning $version the boolean negation of an undefined variable. Undefined is boolean false, and so the negation is boolean true or 1.
If you read very much on perl, you're bound to come across the advice to use strict and warnings. Had you done that, it would have told you, among other things:
Global symbol "$oldVersion" requires explicit package name at - line 21.
This means that you didn't declare $oldVersion as lexical (my) or package-level (our) in this package, so if you want to use it, please include the package where you're getting it. In a vast majority of cases, a seasoned Perl programmer will recognize this as "Ugh, I didn't declare $oldVersion!" and the reason is that you declared $oldversion.
Your use of split doesn't make a lot of sense here. What you really want are the two digits following the CVP-LATEST-5.3.0. string. You're also not really doing anything by assigning one variable to another with the addition of quotes ($newPage = "$simplePage").
And, of course, as others have pointed out, the comparison is != not =!.
I'd rewrite this as:
use strict;
use warnings;
use LWP::Simple;
my $oldVersion = 36;
my $url = 'http://www.google.com/isos/preFCS5.3/LATESTGOODCVP/';
my $newPage = get($url)
or die "Cannot retrieve contents from $url\n";
if ( $newPage =~ /href=\"CVP-LATEST-5\.3\.0\.(\d\d)/ ) {
my $version = $1;
if ( $version != $oldVersion ) {
my $status = getstore($url . "CVP-LATEST-5.3.0.$version.iso",
"CVP-LATEST-5.3.0.$version.iso");
} else {
print "Already at most recent version\n";
}
} else {
die "Cannot find version tag in contents from $url\n";
}

How can I parse people's full names into user names in Perl?

I need to convert a name in the format Parisi, Kenneth into the format kparisi.
Does anyone know how to do this in Perl?
Here is some sample data that is abnormal:
Zelleb, Charles F.,,IV
Eilt, John,, IV
Wods, Charles R.,,III
Welkt, Craig P.,,Jr.
These specific names should end up as czelleb, jeilt, cwoods, cwelkt, etc.
I have one more condition that is ruining my name builder
O'Neil, Paulso far, Vinko Vrsalovic's answer is working the best when weird/corrupt names are in the mix, but this example above would come out as "pneil"... id be damned below judas if i cant get that o between the p and the n
vinko#parrot:~$ cat genlogname.pl
use strict;
use warnings;
my #list;
push #list, "Zelleb, Charles F.,,IV";
push #list, "Eilt, John,, IV";
push #list, "Woods, Charles R.,,III";
push #list, "Welkt, Craig P.,,Jr.";
for my $name (#list) {
print gen_logname($name)."\n";
}
sub gen_logname {
my $n = shift;
#Filter out unneeded characters
$n =~ s/['-]//g;
#This regex will grab the lastname a comma, optionally a space (the
#optional space is my addition) and the first char of the name,
#which seems to satisfy your condition
$n =~ m/(\w+), ?(.)/;
return lc($2.$1);
}
vinko#parrot:~$ perl genlogname.pl
czelleb
jeilt
cwoods
cwelkt
I would start by filtering the abnormal data so you only have regular names. Then something like this should do the trick
$t = "Parisi, Kenneth";
$t =~ s/(.+),\s*(.).*/\l$2\l$1/;
Try:
$name =~ s/(\w+),\s(\w)/$2$1/;
$name = lc $name;
\w here matches an alphanumerical character. If you want to be more specific, you could also use [a-z] instead, and pass the i flag (case insensitive):
$name =~ s/([a-z]+)\s([a-z])/$2$1/i;
Here's a one line solution, assuming you store all the names in a file called "names" (one per line) and you will do duplicated name detection somehow later.
cat names | perl -e 'while(<>) {/^\s*(\S*)?,\s*(\S)/; print lc "$2$1\n";}' | sed s/\'//g
It looks like your input data is comma-separated. To me, the clearest way to do this would be split into components, and then generate the login names from that:
while (<>) {
chomp;
my ($last, $first) = split /,/, lc $_;
$last =~ s/[^a-z]//g; # strip out nonletters
$first =~ s/[^a-z]//g; # strip out nonletters
my $logname = substr($first, 0, 1) . $last;
print $logname, "\n";
}
$rowfetch =~ s/['-]//g; #All chars inside the [ ] will be filtered out.
$rowfetch =~ m/(\w+), ?(.)/;
$rowfetch = lc($2.$1);
this is how I ended up using Vinko Vrsalovic's solution... its inside a while loop that goes through a sql query result ... thanks again vinko
This should do what you need
use strict;
use warnings;
use 5.010;
while ( <DATA> ) {
say abbreviate($_);
}
sub abbreviate {
for ( #_ ) {
s/[-']+//g;
tr/A-Z/a-z/;
tr/a-z/ /c;
return "$2$1" if /([a-z]+)\s+([a-z])/;
}
}
__DATA__
Zelleb, Charles F.,,IV
Eilt, John,, IV
Woods, Charles R.,,III
Welkt, Craig P.,,Jr.
O'Neil, Paul
output
czelleb
jeilt
cwoods
cwelkt
poneil

Resources