View Full Version : building array from foreach loop gives blank spaces :(
Hi,
I have built an array from a loop which goes through several files to pick a specific line of data.(email address). Then it puts them into an array however, there is a space between each one and I want to change it to be a comma.
unshift(@email,$email); # builds the array. like this
email1 email2 email3 etc
I want it to be email1,email2,email3,etc
Tried a few things but they throw an error.
What am I looking for? searched google but can't seem to find it.
Bazz
FishMonger
10-30-2005, 09:23 PM
Do you want to fix this when you buid the array or when you output the array?
Is each element of the array a single address or a list of addresses seperated by a space?
If they're single addresses, you'd simply use join to put them together into a scalar.
$emails = join(',', @email);
FishMonger
10-30-2005, 09:37 PM
If each element is a list of addresses, you'd use a regex to substitute the spaces with commas.
s/\s+/,/g for @email;
Then, if needed, you can join the elements with a comma.
Hi FishMonger,
It looks like I might be making it difficult for myself again. here is my code, which is a loop and, on each run, it adds a new email address to the array @email.
if ( open ( DAT, "< $dat_file" ) ) {
while ( my $Line = <DAT> ) {
last if ( index($Line, ':') == -1 );
chomp $Line;
my ( $Keyword, $Value ) = split /:/, $Line, 2; #splits the line at the first : ignoring any others
if ($Keyword eq "client_reference") {
$client_reference = $Value;
} elsif ($Keyword eq "email") {
$email = $Value;
chomp ($email);
} else {
warn "unknown field";
} # end of if conditional
} # end of while loop
close DAT;
unshift(@email,$email);
if I use
$email = join(',', @email); after the last line of my code, it returns 'millions' of commas. otheriwse I see no difference.
If I use
s/\s+/,/g for @email; it adds a comma only in three places, yet retainms all of the spaces, where there are 13 email addresses outputted.
Maybe its my unshift line which causes the error (?), so I'll google more, for a hoped for alternative.
Bazz
FishMonger
10-31-2005, 03:34 PM
Based on what you've posted, @email should only hold 1 element, since you're adding the element after the while loop. With this code, if you have 13 addresses, that could only happen if all 13 are on the same line in the dat_file and it's the last time the Keyword email is found.
How are you determing that there is a space between the addresses? Have you tried using Data::Dumper to see the actual data structure of the @email array?
Can you post the dat_file and the code you used to determine what's in the @email array?
Hi FishMonger,
I should have posted more code (I'll do that now).
The code runs through a series of files and pulls the email address from each, building the array as it does so. None of the flat files has a space at either end of the email address.
the lines are like this:
email:theirbox@theirdomain.com
my $Filepath = "/domains/574/1617/html/FILES/Client_Details";
my ( @listOfFiles, @listOfDirs);
tie my %files, 'IO::Dir', $Filepath;
foreach my $key ( keys %files ) {
next if ( substr($key, 0, 1) eq '.' );
my $isItADir = ( $files{$key}->mode & 0x004000 ) >> 14;
if ( $isItADir == 1 ) {
push @listOfDirs, $key;
} else {
push @listOfFiles, $key;
}
} # end of foreach
if ( @listOfFiles > 0 || @listOfDirs > 0 ) {
my ( $firstFile, $firstDir ) = ( 0, 0 );
foreach my $key ( sort @listOfFiles ) {
my $spiel = '';
if ( $firstFile == 0 ) {
$firstFile = 1;
$spiel = 'Subject:';
}
my $subject = $key;
$subject =~ s/_/ /g;
my $filesubject = $key;
my ( $clientName, $businessType, $businessCounty, $localTourismAuthority ) = split /\_/, $key, 6;
if ( $localTourismAuthority eq $TICBusinessName ) { # make sure this only opens the files for this LTA members
my ($client_reference,$business_name,$address1,$address2,$address3,$post_code,$townland,$county,$grid_r eference,$email,$web_url,$telephone,$fax)=('','','','','','','','','','','','','');
local *DAT;
my $dat_file = "$Filepath/$key";
if ( open ( DAT, "< $dat_file" ) ) {
while ( my $Line = <DAT> ) {
last if ( index($Line, ':') == -1 );
chomp $Line;
my ( $Keyword, $Value ) = split /:/, $Line, 2; #splits the line at the first : ignoring any others
if ($Keyword eq "client_reference") {
$client_reference = $Value;
} elsif ($Keyword eq "email") {
$email = $Value;
chomp ($email);
} else {
warn "unknown field";
} # end of if conditional
} # end of while loop
close DAT;
unshift(@email,$email);
} else {
print <<EOF;
couldn't open file
EOF
} # end of 'if open'
} # end of if match LTA with base Business Name
} # end of sort listOfFiles
} # end of if @listOfFiles
Bazz
FishMonger
10-31-2005, 05:33 PM
It looks like I might be making it difficult for myself again.I agree, you defiantly are making it more difficult than it needs to be. It’ll be a little while before I can work on this, but as soon as I can, I’ll see what I can come up with without drastically reworking your code.
Fishmonger that would be very much appreciated. Thanks.
curiosity asking, are you thinking of a module other than IO::Dir? perhaps data dumper, as you mentioned before, or even another one?
I have no experience with Data Dumper but if it helped to give you a easier starting point I would read up on it and see what I could build.
Bazz
PS
.......... but if it helped to give you a easier starting point .......
unlikely but, I would try :)
FishMonger
10-31-2005, 06:27 PM
For what you're doing, there's no need to use the IO::Dir module. There are other modules that can be used however, Perl has built-in methods that will work just as well. And the test your doing to see if it's a directory can be done with a simple file test.
my $isItADir = 1 if -d $files{$key};
or
-d $files{$key} ? push @listOfDirs, $key : push @listOfFiles, $key;
I use Data::Dumper only as a debugging tool, but it can also be used to output the the data in ways that would normally be very difficult.
http://search.cpan.org/~ilyam/Data-Dumper-2.121/Dumper.pm
FishMonger
10-31-2005, 09:17 PM
I made modifications to most of the obvious issues, but I didn't run any tests.
my $Filepath = "/domains/574/1617/html/FILES/Client_Details";
my ( @listOfFiles, @listOfDirs);
while(<$Filepath/*>) {
-d $_ ? push @listOfDirs, $_ : push @listOfFiles, $_;
}
if ( @listOfFiles && @listOfDirs ) { # both should be true, not either/or
my ( $firstFile, $firstDir ) = ( 0, 0 );
foreach my $key ( sort @listOfFiles ) {
my $spiel = '';
if ( $firstFile == 0 ) {
$firstFile = 1;
$spiel = 'Subject:';
}
my $subject = $key;
$subject =~ s/_/ /g;
my $filesubject = $key;
my ( $clientName, $businessType, $businessCounty, $localTourismAuthority ) = split /\_/, $key, 6;
if ( $localTourismAuthority eq $TICBusinessName ) { # make sure this only opens the files for this LTA members
my ($client_reference,$business_name,$address1,$address2,$address3,$post_code,$townland,$county,$grid_r eference,$email,$web_url,$telephone,$fax)=('','','','','','','','','','','','','');
local *DAT;
my $dat_file = "$Filepath/$key";
if ( open ( DAT, "< $dat_file" ) ) {
while ( my $Line = <DAT> ) {
last if $Line =! /:/;
chomp $Line;
my ( $Keyword, $Value ) = split /:/, $Line, 2; #splits the line at the first : ignoring any others
$Keyword eq "client_reference" ? $client_reference = $Value : $Keyword eq "email" ? unshift(@email, $Value) : warn "unknown field";
}
close DAT;
}
else {
print "couldn't open file";
}
} # end of if match LTA with base Business Name
} # end of sort listOfFiles
} # end of if @listOfFiles
FishMonger
11-01-2005, 02:22 PM
Baz,
Those adjustments I made are merely a starting point in cleaning up the code to make it more efficient, readable, and maintainable. However, that won't solve the problem you asked about. For that we need to look at how you are outputing the array.
Here's a short script that demonstrates how the space is probably being introduced.
#!/usr/bin/perl -w
use Data::Dumper;
@array = qw(one two three);
print Dumper @array;
print @array,$/;
print "@array\n";
The first print statement outputs:$VAR1 = 'one';
$VAR2 = 'two';
$VAR3 = 'three';
The second outputs:onetwothree
The third outputs:one two three
When the @array is inside double quotes, it will be joined with the Output Field Seperator which is a space by default, but can be changed to something else.
If you post the section that outputs the array, we should be able to see what needs to be done to correct this issue.
FishMonger, I really appreciate your time on this.
OK, I tinkered with your code and using your three methods to try out the output of the email address, it does as you said. (That doesn't surprise me, I'm just letting you know). :)
So I shall try to workout a solution while this waits for your next visit.
Thanks FishMonger
Bazz
here's the code to output the email addresses
print <<EOF;
<p>
<b>Recipients Addresses:</b>
<textarea name="recipientsAddresses" rows="5" cols="100">
EOF
#print <<EOF;
#at email = @email <br /> # spaces present
#EOF
print Dumper @email;
#print @email,$/;
#print "@email\n";
print <<EOF;
</textarea><br /><br /></p>
EOF
I tries to do substitution but it didn't work, presumably because, the space is not really part of the item.
Bazz
FishMonger
11-01-2005, 08:21 PM
I'm not sure, but I think the problem is related to your use of the HERE document. Here documents are a form of double quoted strings. We'd need to run some tests but when you print the array in the here document, it is probably joining the elements with Perl's field seperator, hence the added spaces.
Try printing the array outside of the here document and use join to add the comma.
print join(',', @email);
EDIT: Why do you use a here document for single short lines??
EDIT Again :)
print <<EOF;
at email = @email <br /> # spaces present
EOF
could be better written as:
print 'at email = ' . join(',', @email) . "<br />\n"; # commas instead of the spaces
FishMonger
11-01-2005, 08:56 PM
I've ran a test and confirmed that it's due to the here document. Here's my test script and its outpout.
#!c:/perl/bin/perl.exe -w
use CGI qw(:standard);
use Data::Dumper;
@email = qw(one two three);
print header;
print <<EOF;
<p>
<b>Recipients Addresses:</b>
<textarea name="recipientsAddresses" rows="5" cols="100">
EOF
print <<EOF;
at email = @email <br />
EOF
print Dumper @email;
print @email,$/;
print "@email\n";
print join(',', @email);
print <<EOF;
</textarea><br /><br /></p>
EOF
Content-Type: text/html; charset=ISO-8859-1
<p>
<b>Recipients Addresses:</b>
<textarea name="recipientsAddresses" rows="5" cols="100">
at email = one two three <br />
$VAR1 = 'one';
$VAR2 = 'two';
$VAR3 = 'three';
onetwothree
one two three
one,two,three</textarea><br /><br /></p>
FishMonger, thank you.
I wasn't aware of the 'here document' thing and it was that, which caused the problem.
So that is, now, another issue resolved. Yay!!
Bazz
vBulletin® v3.8.2, Copyright ©2000-2012, Jelsoft Enterprises Ltd.