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

I have two while loops that read the same file and it works.
If Possible please advise how I can combine these two and make the script shorter. I tried some ways but couldnt get it to work. Here is the part I am working with:
open(TMPFILE,"<page.html") || die "Cant open: $!"; while (<TMPFILE>) { chomp; my $myFile = join('',<TMPFILE>); if ($myFile =~ /'(\d{3})wordONE/) { $data = $1; } } close TMPFILE; open(TMPFILE,"<page.html") || die "Cant open: $!"; while (<TMPFILE>) { chomp; my $myFile2 = join('',<TMPFILE>); if ($myFile2 =~ /(\d{3})wordTWO/) { $data2 = $1; } } close TMPFILE; #Do stuff with $data and #data2

Replies are listed 'Best First'.
Re: Combining while statements
by broquaint (Abbot) on Jun 17, 2003 at 13:21 UTC
    I don't believe your code is working quite how you think - you're iterating over TMPFILE, then slurping it's contents with the join (which also means you're missing the first line) and then performing a match on that string, repeating the same procedure, and then performing another match on the same string. A simple reduction might look like this (explained below)
    open(TMPFILE, "page.html") or die("Can't open page.html: $!") my($data, $data2); { local $/; local $_ = <TMPFILE>; ($data) = /'(\d{3})wordONE/; ($data2) = /(\d{3})wordTWO/; } close(TMPFILE);
    That slurps TMPFILE (by undefining $/) into a localised $_ then performs two matches on $_ saving the contents captured in the parentheses into the variables $data and $data2 respectively. This should produce the same (and more reliable) result of the code you demonstrated.
    HTH

    _________
    broquaint

(jeffa) Re: Combining while statements
by jeffa (Bishop) on Jun 17, 2003 at 13:24 UTC
    I really wish you would have:
    1. given us a sample of the data file you are working with
    2. shown us what you really want out of that data
    That being said, if the file is small enough, you could just slurp it into a scalar, run a generic regex on that scalar and capture the results into an array:
    open TMPFILE,'page.html' or die "Can't open: $!"; my $data = do {local $/;<TMPFILE>}; my @data = $data =~ /(\d{3})word/g; print "$_\n" for @data;
    hope this helps :)

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
Re: Combining while statements
by Zaxo (Archbishop) on Jun 17, 2003 at 13:31 UTC

    Your while loops are oddly constructed. You are discarding the first line after chomping it and then slurping the rest. Each while loop only runs once.

    Do you mean to do something like this?

    open TMPFILE, "< page.html" or die "Cant open: ", $!; my (@data, @data2); while (<TMPFILE>) { push @data, $1 if /'(\d{3})wordONE/; push @data2, $1 if /(\d{3})wordTWO/; } close TMPFILE;
    I'm made suspicious by your doing this on an html file. Are you doing something better handled by some HTML::Parser module?

    (Added) Thanks, jeffa, for spotting a typo in the code. Repaired.

    After Compline,
    Zaxo

      Thanks for all the responses. I used "join" because I was fetching something that covered two lines. I will now try all your suggestions.
Re: Combining while statements
by Bilbo (Pilgrim) on Jun 17, 2003 at 13:18 UTC

    What have you tried? In what way does it not work?

    Does this do what you mean:

    open(TMPFILE,"<page.html") || die "Cant open: $!"; while (<TMPFILE>) { chomp; my $myFile = join('',<TMPFILE>); if ($myFile =~ /'(\d{3})wordONE/){ $data = $1; } if ($myFile =~ /(\d{3})wordTWO/) { $data2 = $1; } } close TMPFILE;

    You can combine the two if statements into an if .. elsif to speed things up slightly if you assume that no line will match both your patterns.

    Update: While this does combine your two while loops I don't really expect this to do anything sensible (are you sure it works in the version that you had?)

Re: Combining while statements
by castaway (Parson) on Jun 17, 2003 at 13:20 UTC
    What did you try? You didn't say..

    It should be just a case of discarding all lines which are the same, and importing the others into the first while statement: open(TMPFILE,"<page.html") || die "Cant open: $!";
    while (<TMPFILE>)
    {
    chomp;
    my $myFile2 = join('',<TMPFILE>);

    if ($myFile2 =~ /(\d{3})wordTWO/) { $data2 = $1; }
    }
    close TMPFILE;

    C.

Re: Combining while statements
by tcf22 (Priest) on Jun 17, 2003 at 13:21 UTC
    Since you are doing join('',<TMPFILE>);, the whole file is sucked in the the scalar $myFile, so the loop only executes once. Maybe try something like this(untested):
    open(TMPFILE,"<page.html") || die "Cant open: $!"; my $myFile = join('', map {chomp;$_} <TMPFILE>); my ($data1, $data2) = $myFile =~ /'(\d{3})wordONE.*?(\d{3})wordTWO/; print "$data1:$data2\n";
Assigning Flat Files to Arrays
by Dente (Acolyte) on Apr 27, 2004 at 00:47 UTC
    I need something similar to Combining while statements or Re: Combining while statements. The idea is to grab search results out of 2 tab delimited text files but keep the results of each file in separate scalers or maybe arrays to be printed separately later. I have HTML::Parser installed but the script utilizes:
    use Fcntl qw(:DEFAULT :flock); use CGI; use CGI::Carp qw(fatalsToBrowser);
    Example of tab delimited file:
    20645 CJ Sports Sportswear and equipment retailer specialising +in rugby, hockey, netball and cricket. Full product details and o +rdering available online. www.cj-sports.co.uk/ 20660 Gekko Gear Selection of winter sports apparel. + www.gekkogear.com/
    open (SIDX, "$data_dir/search.idx"); open (SIDX2, "$data_dir/search2.idx"); if ($file_locking ne "No"){flock (SIDX, LOCK_SH) or die "Can't set lo +ck for file: $data_dir/search.idx, $data_dir/search2.idx $!\n";} while (defined($line=<SIDX2>) and ($premiumline=<SIDX2>)) { $sline = $line, $premiumline; foreach $kwr (@skeyw, @premiumkeyw) { if (($sline =~ /$kwr/i) and ($kwr ne "")) { $toadk = "true"; } } if ($toadk eq "true") { $resultline[$icnt] = $line; $toadk = false; $icnt++; } } #if ($file_locking ne "No"){flock (CIT, LOCK_UN);} close (SIDX); close (SIDX2); }

      Why not use something like DBD::AnyData to ease your burden. I renamed your files to search1.idx and search2.idx ... it is important that you put a '1' in the first file in order to be able to "generically" loop each search file with the same code. You also need to add column headers to each of the tab delimited files like so:

      id      name    description     url
      20660   Gekko Gear   Selection of winter sports apparel.   www.gekkogear.com/
      
      Then, try this code:
      use strict; use warnings; use Data::Dumper; use DBI; my $dbh = DBI->connect('dbi:AnyData(RaiseError=>1):'); for (1,2) { $dbh->func("search$_", 'Tab', "search$_.idx", 'ad_catalog'); my $sth = $dbh->selectcol_arrayref(" SELECT url FROM search$_ WHERE description like '%Sport%' OR description like '%sport%' "); print Dumper $sth; }
      Yes, that is magic. :) Now, i merely Dumped the resulting array reference of URL's to STDOUT, you said that you need to store them in seperate arrays ... but i don't even see why you store what you are searching in two seperate files in the first place ... this should get you going though.

      jeffa

      L-LL-L--L-LL-L--L-LL-L--
      -R--R-RR-R--R-RR-R--R-RR
      B--B--B--B--B--B--B--B--
      H---H---H---H---H---H---
      (the triplet paradiddle with high-hat)