perl: useing commas in hash values - string

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" }

Related

compare string variables in perl

I have an if clause in perl, where as condition I need to compare two variables if they match as strings. But my code doesnt work and the strings never match:
if(trim($file) eq trim($fields[0])) {
print "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO";
}
For the definition of trim I have used:
sub trim($)
{
my $string = shift;
$string =~ s/^\s*(.*?)\s*$/$1/;
return $string;
}
Moreover I have used this before for the variables to compare.
my #fields= split(/\;/,$_);
Any help? Thanks!
Your code is correct, so your strings are different.
To find the differences, I recommend the following code since it will reveals differences that might not be noticeable by just printing the strings:
use Data::Dumper;
{
local $Data::Dumper::Useqq=1;
print Dumper($file, $fields[0]);
}
By the way, the following is more elegant and possibly faster:
sub trim {
my $string = shift;
$string =~ s/^\s+//;
$string =~ s/\s+\z//;
return $string;
}
And IIRC, the following is even faster (for a drop in readability):
sub trim {
my $string = shift;
$string =~ s/^\s+|\s++\z//g;
return $string;
}

perl encryption script IDEA

Hi everyone im making a perl script to encrypt and decrypt text, i just have started i have this:
#!/usr/bin/perl
use Crypt::IDEA;
my $key = pack("H32", "0123456789ABCDEF0123456789ABCDEF");
my $cipher = new IDEA $key;
my $palabra= "plaintex";
my $ciphertext = $cipher->encrypt($palabra); # NB - 8 bytes
print unpack("H16", $ciphertext), "\n";
my $plaintext = $cipher->decrypt($ciphertext);
print $plaintext , "\n";
The trouble is the text to encrypt must be of 8 bytes of length. why? if i put "plaintext" instead "plaintex" gives me error.
input must be 8 bytes long at /usr/lib/perl5/site_perl/Crypt/IDEA.pm line 62.
Wrap Crypt::IDEA with Crypt::CBC - it will allow to use non-aligned data length. See doc for Crypt::CBC.
This is because IDEA and many other crypt algorithms are block encryption algorithms. This means they operate with blocks of data of specified size, so data you encrypting must be prepared (padded with zeros or whatever)
Try Crypt::CBCeasy
#!/usr/bin/perl --
use strict; use warnings;
use Crypt::CBCeasy qw/ IDEA /;
my $key = 'shabba';
my $text = "plaintex"; ## not a file, not -f -r $text
my $crypted = IDEA::encipher( $key, $text );
my $detext = IDEA::decipher( $key, $crypted );
print join "\n", $key, $text, unpack( 'H*', $crypted ), $detext, '';
__END__
shabba
plaintex
53616c7465645f5fb5ec01275eb466c4b9b69f3edb7568b42c1713416d33b7aa
plaintex

What's a good character to separate strings with leading white-spaces?

I'm using the null character (\0) as a separator to keep the strings leading white-spaces after the sprintf. But the strings with the null character don't work (in this case) with the Curses addstr function.
Is there some suitable character to replace the \0 for this purpose?
#!/usr/bin/env perl
use warnings;
use 5.12.0;
sub routine {
my #list = #_;
#list = map{ "\0".$_."\0"; } #list;
# ...
# ...
#list = map{ sprintf "%35.35s", $_ } #list;
# ...
# ...
my $result = $list[5];
$result =~ s/\A\s+\0//;
$result =~ s/\0\s+\z//;
return $result;
}
What about using some pretty print module from CPAN?
http://metacpan.org/pod/Data::Format::Pretty::Console
http://metacpan.org/pod/Text::Tabulate

Perl: Removing characters up to certain point.

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).

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