Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

Re^2: Create output from Perl hash

by gbwien (Sexton)
on Feb 13, 2018 at 12:30 UTC ( #1209059=note: print w/replies, xml ) Need Help??


in reply to Re: Create output from Perl hash
in thread Create output from Perl hash

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

Replies are listed 'Best First'.
Re^3: Create output from Perl hash
by Laurent_R (Canon) on Feb 13, 2018 at 14:03 UTC
    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.

      Hi Laurent_R, I ran your code, if there are multiple records in the file only the first is printed. I think the problem is the print "$line\n"; Also the 91436903000 should be 1/1/1/0-436903000 Thank you again, this is a real help for me to get back into perl.

      <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
        if there are multiple records in the file only the first is printed.
        Sure, you did not describe your input data and only gave one sample. I based the suggested program on your data sample. The first sample you gave only had one "CF" line, so I made the first program based on that sample. And it worked.

        Then you gave another sample with several "CF" lines (but still only one record block), so I changed my program to fit this new data sample. And it worked.

        Now, you're saying that there can be several record blocks. How were we supposed to guess that? Well, in fact, I sort of guessed it would plausibly be the case, but I could not write a program based on an inexistent data sample.

        So this is the third version:

        use strict; use warnings; my $line; while (<DATA>) { if (/^\s*MSISDN=(\d+);/) { print "$line\n" if defined $line; $line = $1 ; } 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__ # --> Here, the data with two record blocks you presented just above
        And this processes your two record blocks and 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/91436903000 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/91436903000
        This is presumably what you want, except for the number at the end of the line, which is discussed just below.
        Also the 91436903000 should be 1/1/1/0-436903000
        OK, fine, but you're not telling how to derive 436903000 from 91436903000. Should we just remove the first two digits in all cases? Or should we remove 91 when the number starts with 91? Or should we remove any digits until we find 43? Or is it something else? How are we supposed to know if you don't tell us?

        So I did not change that, because did not specify the rule to be applied to derive the number you want to print. I guess it is probably fairly easy and you can probably make the change yourself.

        My advice would be as step 1 - extract the data you need into a structure. Multiple records with a common key suggests a HashOfArrays. For example

        #!/usr/bin/perl use strict; use warnings; use Data::Dumper; my $key1 = 'MSISDN'; my $key2 = 'CF'; my $sep = ','; # input my $rec = {}; while (my $line = <DATA>){ next if $line =~ /BEGINFILE/; #skip first line chomp $line; $line =~ s/^\s+|;$//g; # remove leading whitespace and ; if ($line =~ /SUBBEGIN/){ $rec = {}; # start new record } elsif ($line =~ /SUBEND/){ if (defined $rec->{$key1} && defined $rec->{$key2}){ output_record($rec) ; } } else { my ($key,$value) = split /=/,$line; push @{$rec->{$key}},$value if ($key); } } # output sub output_record { my $rec = shift; print Dumper \$rec; } __DATA__

        If that works, then step 2 work on your transformation and output code to replace Dumper.

        sub output_record { my $rec = shift; # print Dumper \$rec; my $MSISDN = $rec->{$key1}[0]; # single my @CF = @{$rec->{$key2}}; # multiple for (@CF){ s{(CF.*-ALL-PROV)-NONE.*}{$1-1/1/1/0}; s{(CF.*-TS10-(?:REG|ACT))-91(\d*).*}{$1-1/1/1/0-$2}; } print join $sep,$MSISDN,@CF; print "\n"; }
        poj

      Hi Laurent_R, I ran your code, if there are multiple records in the file only the first is printed. I think the problem is the print "$line\n"; Also the 91436903000 should be 1/1/1/0-436903000 Thank you again, this is a real help for me to get back into perl.

      <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

      Sorry about that, I just updated it before you answered. I'll give that a go. Thanks again

        It's great to edit posts, especially to fix typos that make code un-runnable or when data doesn't match output. But when editing your posts, please make sure you do not destroy context (study How do I change/delete my post?, especially the section "It is uncool...") -- make sure you indicate within the edited post that it has been edited, and how you edited it, so that replies don't become meaningless/confusing. You could go back now, and indicate what you changed, to make the thread more understandable to people reading in the future.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1209059]
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (3)
As of 2018-06-23 20:48 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?



    Results (125 votes). Check out past polls.

    Notices?