CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Beginner:
Creating a hash and assigning this has its keys and values

 



adamjazz1
Novice

Jul 17, 2009, 11:41 PM

Post #1 of 20 (2708 views)
Creating a hash and assigning this has its keys and values Can't Post

Hi everyone,

I am having trouble with this has business. I have a .txt file I want to open, then I want to have this text file assigned to a hash. But this has has to have specific data from this .txt file as a key -> value pair.

Also, if someone could give me hints to proper perl code formatting I would appreciate that as well.



Code
#!/usr/bin/perl 


$ensname="/#######/#####.txt";
$ensdir="/#######/####.txt";

my %dirhash;
# fill in $dirhash

open ( DIR, $ensdir );
while ( $dir1=<DIR>) {
@dirnames=$dir1;

chomp(@dirnames);

for (my $ia=1; $ia <= $#dirnames; $ia++) {
if ($dirnames[$ia]=~/(^T\d\d\d\d)(\d{1,6}ens\d{1,3})/){
my $tarname=$1;
my $direct=$2;
printf "%s %s", $tarname, $direct;

}
}
open (ENS, $ensname);
while ($ensname1 = <ENS>) {
chomp $ensname1;
@ensnames= split(/D/,$ensname1);
#print "@ensnames\n";
for (my $i=1; $i <= $#ensnames; $i++){
if ($ensnames[$i]=~/(\d):([0-9\-\s]+)/) {
my $target=$ensnames[0];
my $domain=$1;(
my $nsel=$2;
$nsel=~s/^\s+//g;
$nsel=~s/\s+$//g;
$nsel=~s/\s+/_/g;
#printf "%s %s, $domain, $nsel";


That is what I have so far. My $ensdir .txt has a format like this:
"T0### ### ### ens###"(where the # are digits) How would I parse this .txt to assign my hash like this: key="T0###" => value="### ### ens###" There are multilple lines to this code so I would want it read line by line, correct?
Ultimately I want to have this key be compared to the variable in the first .txt file to make sure they are the same and then use the value of the $ensdir used in my code. If more clarification is needed, let me know.

Thanks for your help!


rork
User

Jul 18, 2009, 8:19 AM

Post #2 of 20 (2702 views)
Re: [adamjazz1] Creating a hash and assigning this has its keys and values [In reply to] Can't Post

Yes you would like to read the file line by line, extract the key and value from each line and fill the hash with that. Using a regexp seems fine to extract the key and value. In your code your regexp doesn't seem to match the example line your giving:

\d{1,6} matches 1 to 6 digets,so it lacks the space in the middle and the space between this block and "ens" in your example.

Also in this code you don't populate the hash.

About code formatting (which is personal): I would indent each block you use with spaces and add the ending of the block on the same indention as the statement with which the block started. For example:

Code
#!/usr/bin/perl 
use strict;
use warnings;

open(FILE, "<", "filename.txt") or die "Can't open FILE ($filename) for reading: $!;
while (my $line = <FILE>) {
chomp($line);
if ($line eq "foo") {
# do something
}
}
close(FILE);


I also noted you added a print statement (either you need it or for debugging which is great):

Code
printf "%s %s", $tarname, $direct;

However it would print the same if $tarname = "T0###" and $direct = "### ### ens###" or $tarname = "T0### ###" and $direct = "### ens###"
It's better to make it more clear what exactly is the key and value and to add a newline to make it more readable:

Code
printf "Key: %s Value: %s\n", $tarname, $direct;

--
Don't reinvent the wheel, use it, abuse it or hack it.


adamjazz1
Novice

Jul 18, 2009, 11:40 AM

Post #3 of 20 (2695 views)
Re: [rork] Creating a hash and assigning this has its keys and values [In reply to] Can't Post

Thanks for the reply rork!

About my regex statement, how do I match the spaces between the T0### ### ### ens###. Also, I did not mention that the numbers can either be 2 or 3 digits.
Would it look something like this: /(T0\d{3})([0-9a-z\s+])/
(the T0### will always have 3 digits).

About populating the hash, can I do this after I get a correct regex match? I was thinking of something like this:
%hash={key}=>{value} (I think that is the format).

Yes, my print statements are for debugging and I will need them later on.

Thank you for your formatting suggestion, I need to write neater code.

Thank you for your input rork!


KevinR
Veteran


Jul 18, 2009, 12:58 PM

Post #4 of 20 (2693 views)
Re: [adamjazz1] Creating a hash and assigning this has its keys and values [In reply to] Can't Post

this part here makes no sense:


Code
open ( DIR, $ensdir );  
while ( $dir1=<DIR>) {
@dirnames=$dir1;

chomp(@dirnames);

for (my $ia=1; $ia <= $#dirnames; $ia++) {
if ($dirnames[$ia]=~/(^T\d\d\d\d)(\d{1,6}ens\d{1,3})/){
my $tarname=$1;
my $direct=$2;
printf "%s %s", $tarname, $direct;

}
}


Does any of that actually do something useful?
-------------------------------------------------


adamjazz1
Novice

Jul 18, 2009, 6:52 PM

Post #5 of 20 (2681 views)
Re: [KevinR] Creating a hash and assigning this has its keys and values [In reply to] Can't Post

KevinR,

At the moment, no it does not do anything useful. I want to populate a hash with the data in $ensdir. It is formatted like this: T0### ### ## ens###
(where the #'s are numbers)

I am having trouble with my regex match, and populating the hash with the appropriate key=> value. I would like the T0### to be the key and the value should be ### ### ## ens### (with this second match the numbers will either be 2 or 3 digits).

Thanks for your input.


KevinR
Veteran


Jul 18, 2009, 7:15 PM

Post #6 of 20 (2677 views)
Re: [adamjazz1] Creating a hash and assigning this has its keys and values [In reply to] Can't Post

Assuming there is nothing else on the lines you are parsing besides T0### ### ## ens###


Code
my %hash; 
open ( my $FH, $ensname ) or die "$!";
while ( my $line = <$FH>) {
chomp $line;
my ($key, $value) = split(/\s+/,$line,2);
$hash{$key} = $value;
}
close $FH;
foreach my $key (keys %hash) {
print "$key = $hash{$key}\n";
}

-------------------------------------------------


(This post was edited by KevinR on Jul 18, 2009, 7:34 PM)


adamjazz1
Novice

Jul 19, 2009, 1:43 AM

Post #7 of 20 (2669 views)
Re: [KevinR] Creating a hash and assigning this has its keys and values [In reply to] Can't Post

KevinR, thanks it is working great. I do have a couple questions though.



Code
my ($key, $value) = split(/\s+/,$line,2);


In this code above how exactly does this split statement work with the two variables. If I understand it correctly, it splits the lines by more than one white space.
What I don't understand is why do you have 2 vars declared beforehand. and after the match, why is there $line and 2? Why is 2 there?

Lets say I wanted to take the value from this hash and compare it to another piece of data later in the text to confirm that it is the correct #.

Thank you for your help KevinR.


KevinR
Veteran


Jul 19, 2009, 9:51 AM

Post #8 of 20 (2657 views)
Re: [adamjazz1] Creating a hash and assigning this has its keys and values [In reply to] Can't Post


In Reply To
KevinR, thanks it is working great. I do have a couple questions though.



Code
my ($key, $value) = split(/\s+/,$line,2);


In this code above how exactly does this split statement work with the two variables. If I understand it correctly, it splits the lines by more than one white space.
What I don't understand is why do you have 2 vars declared beforehand. and after the match, why is there $line and 2? Why is 2 there?

Lets say I wanted to take the value from this hash and compare it to another piece of data later in the text to confirm that it is the correct #.

Thank you for your help KevinR.


The lines of your file look like this:

T0### ### ## ens###

as the code reads the file it assigns each line to $line

the fields in the lines are seperated by a space (or possibly by spaces) so you can use the split() function to split the lines into 2 fields using\s+ as the pattern to split the lines.
The number 2 tells the split function to only split the line once (which breaks it into 2 tokens) so its split on the first instance of \s+ found in the line and each token that the split function returns is assigned respectively to the list on the left side:

my ($key, $value) = split(/\s+/,$line,2);

Your second question is a bit vague. But to compare bits of data you use == for numbers or eq for strings (assumes you are comparing for equality and not inequality).

If you want to elaborate more on that part of your question maybe I can be more helpful.
-------------------------------------------------


(This post was edited by KevinR on Jul 19, 2009, 9:55 AM)


adamjazz1
Novice

Jul 19, 2009, 7:58 PM

Post #9 of 20 (2652 views)
Re: [KevinR] Creating a hash and assigning this has its keys and values [In reply to] Can't Post

KevinR- Thank you for your reply.

To clarify my second question, I would like to take the key(T0###) from $ensdir .txt file and compare it to $target=$ensnames[0];(they are the same T0### format).

So I think it would look like this: if $key eq $target(i'm not sure, I am thinking I have to reference the hash) if these strings match I would want to pass the $value string down to my second printf statement.

I thank you for your assistance.


KevinR
Veteran


Jul 19, 2009, 8:29 PM

Post #10 of 20 (2651 views)
Re: [adamjazz1] Creating a hash and assigning this has its keys and values [In reply to] Can't Post


In Reply To
KevinR- Thank you for your reply.

To clarify my second question, I would like to take the key(T0###) from $ensdir .txt file and compare it to $target=$ensnames[0];(they are the same T0### format).

So I think it would look like this: if $key eq $target(i'm not sure, I am thinking I have to reference the hash) if these strings match I would want to pass the $value string down to my second printf statement.

I thank you for your assistance.


Its probably just me, but I don't understand what you are trying to explain. But if you need to see if the key of a hash equals the same value as another string then you have to loop through the hash keys and compare them to your other string:


Code
foreach my $key (keys %hash) { 
if ($key eq $otherstring) {
do something
}
}

-------------------------------------------------


ichi
User

Jul 19, 2009, 11:02 PM

Post #11 of 20 (2650 views)
Re: [@OP] Creating a hash and assigning this has its keys and values [In reply to] Can't Post

@OP it would be better to just explain , with examples of your input file, what you want to get eventually, showing your final output.


(This post was edited by ichi on Jul 20, 2009, 12:16 AM)


adamjazz1
Novice

Jul 19, 2009, 11:43 PM

Post #12 of 20 (2645 views)
Re: [ichi] Creating a hash and assigning this has its keys and values [In reply to] Can't Post

I think I can explain what I am looking to get in the end.

The $ensdir text file contains T0### and a corresponding ---
###/###/ens## this last piece of data is actually a directory.
(my final code will include a sprintf command).

The $ensname text file also contains a T0###, I need to compare the $ensdir and the $ensname T0### to make sure that they are equal.
If they are equal I want to pass the value that is in the $ensdir populated hash.

I need a way to get this directory information into my second printf command, after comparing the T0### strings.

Thank you for all of your input guys, I appreciate it.
(if more clarification is needed, just ask)


ichi
User

Jul 20, 2009, 12:20 AM

Post #13 of 20 (2644 views)
Re: [adamjazz1] Creating a hash and assigning this has its keys and values [In reply to] Can't Post

like i said, post a sample of both files. If its sensitive, give some fake data but try not to change the structure much.
To check whether they are equal is pretty easy, but pretty difficult to suggest code for you, not without some hint on the rest of the data structures. That's why i requested samples...get it?


adamjazz1
Novice

Jul 20, 2009, 12:35 AM

Post #14 of 20 (2642 views)
Re: [adamjazz1] Creating a hash and assigning this has its keys and values [In reply to] Can't Post

Sure no problem, here is a sample of the $ensdir file: ----
T0111 43 67 ens172

and $ensname: T0123 D1:1_122 123_167 D2:24-154
(each of the lines in $ensname are different in terms of number of D#'s)

Thank you ichi, if you need anymore let me know.


ichi
User

Jul 20, 2009, 12:58 AM

Post #15 of 20 (2641 views)
Re: [adamjazz1] Creating a hash and assigning this has its keys and values [In reply to] Can't Post

something to think about.

Code
open(ENDSDIR,"<file") or die "Cannot open $endsir:$!\n"; 
open(ENDSNAME,"<file1") or die "Cannot open $endname:$!\n";
while(<ENDSDIR>){
if( /^T/ ){
$numdir = substr( ((split /\s/))[0] , 2);
last;
}

}
close(ENDSDIR);
while(<ENDSDIR>){
if (/^T/){
$numname = substr( ((split /\s/))[0] , 2);
if ( $numname eq $numdir ){
print "same number..... now what?? "
last;
}
}

}
close(ENDSNAME);



adamjazz1
Novice

Jul 20, 2009, 9:33 AM

Post #16 of 20 (2622 views)
Re: [ichi] Creating a hash and assigning this has its keys and values [In reply to] Can't Post

Thanks for your help ichi.

Your code works just like I wanted it to, but I have realzed that I need some adjustments. I am having trouble figuring it out.

I edited my $ensdir as this: T0489/136/120/ens229
(I need the /'s to navagate to the correct dir). I edited the code to this:

Code
 if( /^T/ ){ 
$numdir = substr( ((split /\//))[0] ,0);



I have achieved a match with $ensname and $ensdir with respect to T0###.

I can't figure out how to get the /136/120/ens229 data assigned to a variable to use in my final sprintf statement.

Ultimately I need it to print like this:
randomscript.pl -dir /136/120/ens229

Thank you for your help, you have taught me a lot!


adamjazz1
Novice

Jul 22, 2009, 5:01 PM

Post #17 of 20 (2599 views)
Re: [adamjazz1] Creating a hash and assigning this has its keys and values [In reply to] Can't Post

Sorry for the bump, but I have a quick question.

With regards to scope and variables.


Code
open(ENDSDIR,"<file") or die "Cannot open $endsir:$!\n";  
open(ENDSNAME,"<file1") or die "Cannot open $endname:$!\n";
while(<ENDSDIR>){
if( /^T/ ){
$numdir = substr( ((split /\s/))[0] , 2);
last;
}

}
close(ENDSDIR);
while(<ENDSDIR>){
if (/^T/){
$numname = substr( ((split /\s/))[0] , 2);
if ( $numname eq $numdir ){
print "same number..... now what?? "
last;
}
}

}
close(ENDSNAME);


Can the vars $numdir and $numname be accessed outside of their respected while statements?

Can I declare them at the beginning and have other statements access them?


ichi
User

Jul 22, 2009, 6:27 PM

Post #18 of 20 (2596 views)
Re: [adamjazz1] Creating a hash and assigning this has its keys and values [In reply to] Can't Post


In Reply To

Can the vars $numdir and $numname be accessed outside of their respected while statements?

Can I declare them at the beginning and have other statements access them?


why don't you print them out after the while loops and see ? its all about experimentation and exploration. you will find it more satisfying than me telling you the answers.


adamjazz1
Novice

Jul 27, 2009, 1:00 PM

Post #19 of 20 (2568 views)
Re: [ichi] Creating a hash and assigning this has its keys and values [In reply to] Can't Post

I finally finished my script.

Code
#!/usr/bin/perl 

$ensname="/####/domainsrev.txt";
$ensdir="/#####/ensdir.txt";

my %dirhash;
my $domkey;
my $domvalue;
my $target;
open(my $ENSDIR, $ensdir) or die "Cannot open $ensdir:$!\n";
open(ENDSNAME, $ensname) or die "Cannot open $ensname:$!\n";

while ( my $line= <$ENSDIR> ) {
chomp $line;
($domkey, $domvalue) = split(/\//,$line,2);
$dirhash{$domkey} = $domvalue;
}
foreach $domkey (keys %dirhash) {

}

while ($ensname1 = <ENDSNAME>) {
chomp $ensname1;

@ensnames= split(/D/,$ensname1);

for (my $i=1; $i <= $#ensnames; $i++){

if ($ensnames[$i]=~/(\d):([0-9\-\s]+)/) {
$target=$ensnames[0];
my $domain=$1;
my $nsel=$2;
$nsel=~s/^\s+//g;
$nsel=~s/\s+$//g;
$nsel=~s/\s+/_/g;
$target=~s/\s+$//g;

printf "models/%s us0D%d genericD%d, $dirhash{$target},$domain,$domain,;


}
}
}
close(ENS);
close $DIRENS;


Thanks for all of your help guys!


FishMonger
Veteran / Moderator

Jul 27, 2009, 1:28 PM

Post #20 of 20 (2567 views)
Re: [adamjazz1] Creating a hash and assigning this has its keys and values [In reply to] Can't Post

EVERY Perl script you write should include the warnings and strict pragmas.

Code
use strict; 
use warnings;



Code
 foreach  $domkey (keys %dirhash)  {  

}

That foreach loop isn't doing anything, so you should remove it.


Code
open(ENDSNAME, $ensname) or die "Cannot open $ensname:$!\n";

Would be better witten as:

Code
open(my $ENDSNAME, '<', $ensname) or die "Cannot open $ensname:$!\n";


Your code indentation is inconsistent.

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives