Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Create output from Perl hash

by gbwien (Sexton)
on Feb 13, 2018 at 10:20 UTC ( #1209051=perlquestion: print w/replies, xml ) Need Help??
gbwien has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks, I have an input file which I am parsing through using a hash to extract values. I've been out of perl for a bit, the following is an example of the input file, maybe you can help?

<BEGINFILE> <SUBBEGIN IMSI=23341400010332; MSISDN=411206901000; CF=CFU-ALL-PROV-NONE-YES-NO-NONE-YES-65535-NO-NO-NO-NO-NO-NO-NO-NO +-NO-NO; <SUBEND

My perl code below:-

#!/usr/bin/perl use strict; use warnings; use Data::Dumper; #define files my $HSSIN='D:\testproject\HSS-export.txt'; my $sep = ","; my $key1 = 'MSISDN'; my $key2 = 'CF'; my $MSISDN; my $CF; #1. normalise test file open (INFILE, $HSSIN) or die "Cant open input file"; open (OUTFILE,"> $ofile" ) or die "Cant open file"; while (my $myline=<INFILE>) { next if $myline =~ /(<BEGINFILE>)/; #skip first line chop($myline); $myline=~ s/(\t)(.*)/$2/g; #remove all tabs $myline =~ /(<SUBBEGIN)(.*)(<SUBEND)/g; #record start end pos my $line = $2; my %hash = split(/=/,$line); #print Dumper \%hash; if (exists($hash{$key1})) { $MSISDN = $hash{$key1}; #print "$MSISDN\n"; } if (exists($hash{$key2})) { $CF = $hash{$key2}; $CF =~s /(CFU-ALL-PROV|CFB-ALL-PROV|CFNRY-ALL-PROV|CFNRC-AL +L-PROV)-(NONE)(.*)?/$1\-1\/1\/1\/1\/0/; $CF =~s /(CFD-TS10-ACT-|CFU-TS10-ACT-|CFD-TS10-REG-)((91)(\ +d*)?)(.*)/$1$4/; #print "$CF\n"; } } #print $MSISDN,$sep,$CF; close INFILE;

I do not know how to get the output I need? $MSISDN,$CF

 411206901000,CFU-ALL-PROV-NONE-YES-NO-NONE-YES-65535-NO-NO-NO-NO-NO-NO-NO-NO-NO-NO

Thank you, Graham

Replies are listed 'Best First'.
Re: Create output from Perl hash
by choroba (Bishop) on Feb 13, 2018 at 10:29 UTC
    What should this do?
    $myline =~ /(<SUBBEGIN)(.*)(<SUBEND)/g;

    You're reading the file line by line. Your sample input contains the SUBBEGIN and SUBEND markers on separate lines. Is it possible to have them on the same line?

    It's unclear how one should get from the sample input to the expected output. Can you describe the algorithm? See also SSCCE.

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

      The input file contains a starting and ending string, so I am using a regular expression to extract group $2 which is what is between SUBBEGIN and SUBEND. I then split $2 based on the equals sign to create my hash %hash.Then within the while loop and using two separate if statements I use the hash function exists to check if key1 is in the %hash(first if statment) and if key2 is in the %hash (second if statement)

Re: Create output from Perl hash
by Eily (Prior) on Feb 13, 2018 at 10:35 UTC

    I was about to say that since my %hash is inside the loop you get a new empty hash on each iteration, but on closer look it seems you don't even need the hash in the first place. Just check if $line =~ /MSISDN=(.*);/, if true, then $MSISDN is $1 (you don't even have to remove the leading whitespace). But then again your expected output contains a lot of data that is not in your input, so it's very unclear how you are supposed to obtain it.

Re: Create output from Perl hash
by Laurent_R (Canon) on Feb 13, 2018 at 11:15 UTC
    Hi gbwien,

    what you want is not very clear to me and there are some unanswered questions. Just like Eily, I don't think you need a hash at all.

    Assuming the last data line in your post is your desired output, you could try something like this:

    use strict; use warnings; my $msisdn; while (<DATA>) { $msisdn = $1 if /^\s*MSISDN=(\d+);/; if (/\s*CF=([\w-]+);/) { print "$msisdn,$1\n"; } } __DATA__ <BEGINFILE> <SUBBEGIN IMSI=23341400010332; MSISDN=411206901000; CF=CFU-ALL-PROV-NONE-YES-NO-NONE-YES-65535-NO-NO-NO-NO-NO-NO-NO-NO +-NO-NO; <SUBEND
    which will duly print:
    411206901000,CFU-ALL-PROV-NONE-YES-NO-NONE-YES-65535-NO-NO-NO-NO-NO-NO +-NO-NO-NO-NO

      Thanks Laurent_R, Your input pointed me in the correct direction. The input file contains records which I want to parse such that the end result are comma separated lines a more elaborate input file extract.

      <BEGINFILE> <SUBBEGIN IMSI=232191400010332; MSISDN=436906901235; CF=CFU-ALL-PROV-NONE-YES-NO-NONE-YES-65535-NO-NO-NO-NO-NO-NO-NO-NO +-NO-NO; CF=CFB-ALL-PROV-NONE-YES-YES-NONE-YES-65535-NO-NO-NO-NO-NO-NO-NO-N +O-NO-NO; CF=CFNRY-ALL-PROV-NONE-YES-YES-NONE-YES-65535-NO-NO-NO-NO-NO-NO-NO +-NO-NO-NO; CF=CFNRC-ALL-PROV-NONE-YES-NO-NONE-YES-65535-NO-NO-NO-NO-NO-NO-NO- +NO-NO-NO; CF=CFD-TS10-ACT-91496903000-YES-YES-25-YES-65535-YES-YES-NO-NO +-NO-YES-YES-YES-YES-NO; <SUBEND

      In the CF fields I would like to not include in the output anything beyound NONE or 91496903000. I would also like to replace NONE by 1/1/1/0 and the example 9149690300 with 1/1/1/49690300 so the final output of the above given input would be

      436906901235,CFU-ALL-PROV-1/1/1/0,CFB-ALL-PROV-1/1/1/0,CFNRY-ALL-PROV-1/1/1/0,CFNRC-ALL-PROV-1/1/1/0,CFD-TS10-ACT-1/1/1/91496903000
        Maybe you could try this:
        use strict; use warnings; my $line; while (<DATA>) { $line = $1 if /^\s*MSISDN=(\d+);/; if (/\s*CF=([\w-]+?-(?:NONE|\d+))/) { my $add = $1; $add =~ s{(\d+)$}{1/1/1/$1}; $add =~ s{NONE}{1/1/1/0}; $line .= ",$add"; } } print "$line\n"; __DATA__ <BEGINFILE> <SUBBEGIN IMSI=232191400010332; MSISDN=436906901235; CF=CFU-ALL-PROV-NONE-YES-NO-NONE-YES-65535-NO-NO-NO-NO-NO-NO-NO-NO +-NO-NO; CF=CFB-ALL-PROV-NONE-YES-YES-NONE-YES-65535-NO-NO-NO-NO-NO-NO-NO-N +O-NO-NO; CF=CFNRY-ALL-PROV-NONE-YES-YES-NONE-YES-65535-NO-NO-NO-NO-NO-NO-NO +-NO-NO-NO; CF=CFNRC-ALL-PROV-NONE-YES-NO-NONE-YES-65535-NO-NO-NO-NO-NO-NO-NO- +NO-NO-NO; CF=CFD-TS10-ACT-91496903000-YES-YES-25-YES-65535-YES-YES-NO-NO +-NO-YES-YES-YES-YES-NO; <SUBEND
        which prints:
        436906901235,CFU-ALL-PROV-1/1/1/0,CFB-ALL-PROV-1/1/1/0,CFNRY-ALL-PROV- +1/1/1/0,CFNRC-ALL-PROV-1/1/1/0,CFD-TS10-ACT-1/1/1/91496903000
        Please note that your specification and your example output are inconsistent. Your spec says "1/1/1/0" (three 1s) and "1/1/1/49690300" (three 1s, and the trailing 0 removed from 91496903000), and your example says "1/1/1/1/0" (four 1s, not three) and "1/1/1/1/91496903000" (four 1s and the complete number 91496903000). You'll have to adjust the code in accordance with your actual needs.
Re: Create output from Perl hash
by tybalt89 (Priest) on Feb 13, 2018 at 19:37 UTC

    No need for a data struture more complicated than a string.

    #!/usr/bin/perl # http://perlmonks.org/?node_id=1209051 use strict; use warnings; local ($/, $,, $\) = ("<SUBEND\n", ',', "\n"); while(<DATA>) { s~NONE.*~1/1/1/0~g; s~91436903000.*~1/1/1/0-436903000~g; print /MSISDN=(\d+)/, /CF=(.*)/g; } __DATA__ <BEGINFILE> <SUBBEGIN IMSI=232191400010332; MSISDN=436906901235; CF=CFU-ALL-PROV-NONE-YES-NO-NONE-YES-65535-NO-NO-NO-NO-NO-NO-NO-N +O-NO-NO; CF=CFB-ALL-PROV-NONE-YES-YES-NONE-YES-65535-NO-NO-NO-NO-NO-NO-NO- +NO-NO-NO; CF=CFNRY-ALL-PROV-NONE-YES-YES-NONE-YES-65535-NO-NO-NO-NO-NO-NO-N +O-NO-NO-NO; CF=CFNRC-ALL-PROV-NONE-YES-NO-NONE-YES-65535-NO-NO-NO-NO-NO-NO-NO +-NO-NO-NO; CF=CFD-TS10-ACT-91436903000-YES-YES-25-YES-65535-YES-YES-NO-NO-NO +-YES-YES-YES-YES-NO; <SUBEND <BEGINFILE> <SUBBEGIN IMSI=232191400010339; MSISDN=436906901231; CF=CFU-ALL-PROV-NONE-YES-NO-NONE-YES-65535-NO-NO-NO-NO-NO-NO-NO-N +O-NO-NO; CF=CFB-ALL-PROV-NONE-YES-YES-NONE-YES-65535-NO-NO-NO-NO-NO-NO-NO- +NO-NO-NO; CF=CFNRY-ALL-PROV-NONE-YES-YES-NONE-YES-65535-NO-NO-NO-NO-NO-NO-N +O-NO-NO-NO; CF=CFNRC-ALL-PROV-NONE-YES-NO-NONE-YES-65535-NO-NO-NO-NO-NO-NO-NO +-NO-NO-NO; CF=CFD-TS10-ACT-91436903000-YES-YES-25-YES-65535-YES-YES-NO-NO-NO +-YES-YES-YES-YES-NO; <SUBEND

    Outputs:

    436906901235,CFU-ALL-PROV-1/1/1/0,CFB-ALL-PROV-1/1/1/0,CFNRY-ALL-PROV- +1/1/1/0,CFNRC-ALL-PROV-1/1/1/0,CFD-TS10-ACT-1/1/1/0-436903000 436906901231,CFU-ALL-PROV-1/1/1/0,CFB-ALL-PROV-1/1/1/0,CFNRY-ALL-PROV- +1/1/1/0,CFNRC-ALL-PROV-1/1/1/0,CFD-TS10-ACT-1/1/1/0-436903000

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1209051]
Approved by marto
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others contemplating the Monastery: (7)
As of 2018-06-22 21:52 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?



    Results (124 votes). Check out past polls.

    Notices?