Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to process sets of text in a flat file through a perl script and then send them out as emails. The flat file is this sort of format:


|--------------------------------------|

Date: today
Request: text here text here text here
Name: Joe Bloggs
Tel: 0123 45677
email: joebloggs@bloggs.com

|--------------------------------------|

Date: Today
Request: text here text here text here
Name: John Smith
Tel: 0123 45677
email: johnsmith@smith.com

|--------------------------------------|

etc
and I want each set of info sent out to the relevant email address.

I need to separate the sets of data into each request (ie on the '|--------------------------------------|' line) and then run trough the sets of data to print into the email. I tried with the code below but the 'split' doesn't work for finding the end of one request and the start of the next, and then the first line of each request just gets repeated rather than going through them one at a time ie it comes out as:

Today
Today
Today
Today
Today

open(REQUESTS,"/home/picturesea/housekeeping/requestsdeadline3.txt") | +| die "requestsdeadline3 file not found";<br> <br> # Open The Mail Program<br> open(MAIL,"|$mailprog -t");<br> <br> @requests = split(/-|/, <REQUESTS>);<br> foreach $requests (@requests) {<br> print MAIL "Bcc: $requests\n";<br> print MAIL "Subject: PICTURE SEARCH request - deadline expired\n +\n";<br> print MAIL "$requests";<br> print MAIL "$requests";<br> print MAIL "$requests";<br> print MAIL "$requests";<br> }<br> close(REQUESTS);<br>

can anyone help with this? thanks Chris

Replies are listed 'Best First'.
Re: processing text from flat file
by mirod (Canon) on Oct 01, 2001 at 23:11 UTC

    What, nobody has suggested messing with $/ (the record separator)?

    Setting $/ to the |---| line will let you read the records one at a time, without having either to glob the entire file or to buffer the lines.

    #!/bin/perl -w use strict; $/="|--------------------------------------|\n"; <DATA>; # skip the first (empty) record before the first |---| +line while( <DATA>)# read an entire record { chomp; # to get rid of the extra \n that would mess up the spl +it my %data= (m/^([^:]*):([^\n]*)$/mg); # get field name (before the +:) and text (until the \n) for each line # %data now holds the fields and their text, and I prove it: while( my( $field, $text)= each %data) { print "$field: $text\n"; } print "\n"; } __DATA__ |--------------------------------------| Date: today Request: text here text here text here Name: Joe Bloggs Tel: 0123 45677 email: joebloggs@bloggs.com |--------------------------------------| Date: Today Request: text here text here text here Name: John Smith Tel: 0123 45677 email: johnsmith@smith.com |--------------------------------------|

    UpdateOf course the original way to parse the record (%data= split /[:\n]/) breaks if the text includes a : so I replaced it with the regexp.

      Don't go mucking around with special global vars w/o localizing them first (at least, not when giving advice to others)! Even if it doesn't make much of a difference in this small script, it is a bad habit to get into and *will* come back to bite in a longer program.
      #!/bin/perl -w use strict; { local $/="|--------------------------------------|\n"; while( <DATA>) { [SNIP] } [SNIP] } ### Here in the program, the <FH> operator will now behave normally ### Before you could have been burned, since any other calls ### to <FH> would see the specialized value of $/, even calls ### in subroutines. As you can imagine, this is a pain to debug ### Its best to avoid this trap altogether as I have done above.
      Update: Added parenthetical clarification....

      -Blake

Re: processing text from flat file
by jeroenes (Priest) on Oct 01, 2001 at 21:37 UTC
    split works on scalars, not on arrays. So join first:
    @requests = split(/\|\-+\|/, join '', <REQUESTS>);
    Just a minor improvement on the split, mehopes you like it.

    Jeroen
    "We are not alone"(FZ)

Re: processing text from flat file
by suaveant (Parson) on Oct 01, 2001 at 21:39 UTC
    Well, you could use split a lot and do this...
    { my @records; local $/; # allow to read in whole file for(split /\s*\|--------------------------------------\|\s*/, <DAT +A>) { my %rec; next unless /\S/; #check for data for(split "\n", $_) { # split up the datum in a record my($key,$val) = split ':', $_, 2; # split the datum, the , +2 limits split to #only splitting the string into at most 2 pieces, +saving further : $rec{$key} = $val; #store in hash } push @records, \%rec; # store recs in array } for(@records) { #iterate and print, you get the idea print "$_->{Date}\n"; } } __DATA__ |--------------------------------------| Date: today Request: text here text here text here Name: Joe Bloggs Tel: 0123 45677 email: joebloggs@bloggs.com |--------------------------------------| Date: Today Request: text here text here text here Name: John Smith Tel: 0123 45677 email: johnsmith@smith.com |--------------------------------------|
    replace DATA with a proper filehandle to your file...

    If it is a very big file, you might want something that reads line by lines and maintains state, but this is one way to do it...

                    - Ant
                    - Some of my best work - Fish Dinner

Re: processing text from flat file
by meonkeys (Chaplain) on Oct 01, 2001 at 22:22 UTC
    Maybe you really wanted to try Parse::RecDescent...
    #!/usr/bin/perl -w use Data::Dumper; use Parse::RecDescent; use strict; $::RD_HINT = 1; # diagnose common Parse::RecDescent errors $::RD_ERRORS = 1; # report fatal errors $::RD_WARN = 1; # report non-fatal problems my $grammar = q? file : record(s) { my @recs; push @recs, @{$item[1]}; \@recs } record : /\|-{38}\|/ details { my $hr = $item[2] } details : date request name tel email { my $hr = { %{$item[1]}, %{$item[2]}, %{$item[3]}, %{$item[4]}, %{$item[5]} } } date : 'Date: ' /.+/ { {date => $item[2]} } request : 'Request: ' /.+/ { {request => $item[2]} } name : 'Name: ' /.+/ { {name => $item[2]} } tel : 'Tel: ' /.+/ { {tel => $item[2]} } email : 'email: ' /.+/ { {email => $item[2]} } ?; my $text; { local $/ = undef; $text = <DATA>; } my $parser = Parse::RecDescent->new( $grammar ) or die "No parser"; my $tree = $parser->file( $text ); $tree or die "Unable to parse records"; print Dumper( $tree ); __DATA__ |--------------------------------------| Date: today Request: text here text here text here Name: Joe Bloggs Tel: 0123 45677 email: joebloggs@bloggs.com |--------------------------------------| Date: Today Request: text here text here text here Name: John Smith Tel: 0123 45677 email: johnsmith@smith.com |--------------------------------------|
Re: processing text from flat file
by derby (Abbot) on Oct 02, 2001 at 01:57 UTC
    Sniff sniff ... crackle sizzle crackle ...
    Anonymouse monk ... mail ... help ... sets of mail addresses
    smells like spam in here

    -derby - maybe I need to say a few rosaries to help with my sarcasm.