references to filehandle?

S

Stefan H.

the first field of my data is the _name_ of the measure.

I need to create from the big file one file per measure containing only
data from that measure. The name of each file must be the same of
measure: ie

bigfile.csv
123 rms 12 132
2312 qrt 12 231
2342 sse 12 231

rms.csv
123 rms 12 132

qrt.csv
2342 sse 12 231

the measure names are changing in name and number, then I cannot code
it. I'd like to do

sub split_measures {

my (%splits);

for (<MYFILE>) {
$splits{[split /;/]->[1]} = '';
}

for (keys %splits) {
open $_, ">$_.csv";
}

for (<MYFILE>) {
print [split /;/;]->1 $_;
}

the error I get is that "strict refs" doesn't permit that. Why? It's
safe to remove that clause? Is there a better way to do that?


Thanks
Stefan
 
A

A. Sinan Unur

the first field of my data is the _name_ of the measure.

Actually, looking at the lines below, it looks like the second field is the
name of the measure, whatever that might mean.
I need to create from the big file one file per measure containing only
data from that measure. The name of each file must be the same of
measure: ie

bigfile.csv
123 rms 12 132
2312 qrt 12 231
2342 sse 12 231

rms.csv
123 rms 12 132

qrt.csv
2342 sse 12 231

the measure names are changing in name and number, then I cannot code
it. I'd like to do

sub split_measures {

my (%splits);

for (<MYFILE>) {
$splits{[split /;/]->[1]} = '';
}

Ahem ... I do not see anything that is separated using ;
for (keys %splits) {
open $_, ">$_.csv";
}

for (<MYFILE>) {
print [split /;/;]->1 $_;
}

Whoa!

D:\Home\test> perl -c s.pl
Number found where operator expected at s.pl line 14, near "->1"
(Missing operator before 1?)
Scalar found where operator expected at s.pl line 14, near "1 $_"
(Missing operator before $_?)
syntax error at s.pl line 14, near "/;/;"
Missing right curly or square bracket at s.pl line 17, at end of line
s.pl had compilation errors.

Did you actually run this thing? You should always post a short, self-
contained script others can run to see what is going on.
the error I get is that "strict refs" doesn't permit that. Why? It's
safe to remove that clause? Is there a better way to do that?

This is how I might do it:

use strict;
use warnings;

while(<DATA>) {
chomp;
if(my @fields = /^\s*(\d+)\s+(\w+)\s+(\d+)\s+(\d+)\s*$/) {
# Using '>>' so as to account for multiple
# lines for a given measure
if(open my $out, '>>', "$fields[1].csv") {
print $out "@{[ join ';', @fields ]}\n";
} else {
warn "Cannot open $fields[1].csv: $!";
}
}
}

__DATA__
123 rms 12 132
2312 qrt 12 231
2342 sse 12 231

__END__

Sinan.
 
S

Stefan H.

Ahem ... I do not see anything that is separated using ;

sorry, I forgot to mention that the data files are semicolon separated
file
print $out "@{[ join ';', @fields ]}\n";
} else {
warn "Cannot open $fields[1].csv: $!";

you don't close the open filehandles. Is this ok?

Thank you very much.

A curiosity:

my code

for (<MYFILE>) {
$splits{[split /;/]->[1]} = '';
}

for (keys %splits) {
open $_, ">$_.csv";
}

was totally wrong? I mean: is it not possible to open filehandles using
scalar variables like that?

And:
$splits{[split /;/]->[1]} = '';

is it correct?

Thank you again
Stefan
 
J

Joe Smith

Stefan said:
for (keys %splits) {
open $_, ">$_.csv";
}

was totally wrong? I mean: is it not possible to open filehandles using
scalar variables like that?

Use a hash to store lexical file handles. Also use 3-argument open().

my %fh; # Hash of file handles
for (keys %splits) {
open {$fh{$_}},'>>',"$_.csv";
}
...
$name = $fields[1];
print {$fh{$name}} $_;

-Joe
 
M

Michele Dondi

I need to create from the big file one file per measure containing only
data from that measure. The name of each file must be the same of
measure: ie

bigfile.csv
123 rms 12 132
2312 qrt 12 231
2342 sse 12 231

rms.csv
123 rms 12 132

I see *basically* two possible approaches:

1. One-pass, repeatedly open()ing and close()ing FHs in '>>' mode,
2. Two-pass, collecting the data and printing it out later.

If bigfile is not really *too big* I'd favour the second solution.
for (<MYFILE>) {
$splits{[split /;/]->[1]} = '';
^^^
^^^

I assume that fields are really semicolon separated rather than
whitespace separated, so (2) above *could* be something like this:


#!/usr/bin/perl

use strict;
use warnings;

my %data;
while (<>) {
my $m=(split /;/)[1] or
warn("Possibly wrong format!"), next;
$m .= '.csv';
push @{ $data{$m} }, $_;
}

for (keys %data) {
open my $fh, '>', $_ or
die "Can't write to `$_': $!\n";
print $fh @{ $data{$_} };
}

__END__


Of course you could/should add finer checks according to how your real
data looks like, e.g.

(my $n=(split /;/)[1]) =~ /^[a-z]{3}$/ or # ...
for (keys %splits) {
open $_, ">$_.csv";
}

Actually you can't do this, you may at most open a lexical FH and
store it in a hash as a value corresponding to $_.
for (<MYFILE>) {
print [split /;/;]->1 $_;
^^^
^^^

Are you sure? ;-)

As a side note it doesn't really do any harm but it is not necessary
to create an anonymous array to dereference it soon after:

(split /;/)[1]

will do!
the error I get is that "strict refs" doesn't permit that. Why? It's
safe to remove that clause? Is there a better way to do that?

There are many better ways to do that. However now I understand what
you *wanted* to do. Indeed it suggests a viable "mixed" solution in
one pass by means of an orkish manouvre:


#!/usr/bin/perl

use strict;
use warnings;

my %fh;
while (<>) {
my $m=(split /;/)[1] or
warn("Possibly wrong format!"), next;
$m .= '.csv';
select $fh{$m} ||= do {
open my $fh, '>', $m or
die "Can't write to `$_': $!\n";
$fh;
};
print;
}

__END__


Here the possible problem is that depending on how many measures you
really have, you could hit the maximum number of open files your OS
permits...


HTH,
Michele
 
M

Michele Dondi

Sorry, I hadn't read Sinan Unur's reply yet when posting my own...


print $out "@{[ join ';', @fields ]}\n";
^^^^
^^^^

you don't close the open filehandles. Is this ok?

Yes it is. In fact he's using a lexical FH: it will be automatically
closed when going out of scope (or more generally whene there will
remain no references to it).
Thank you very much.

A curiosity:

my code [snip]
was totally wrong? I mean: is it not possible to open filehandles using
scalar variables like that?

It is possible to open FHs using scalar variables. But not *like
that*. For another cmt on your approach, slightly revised, see my
other post in this thread.
And:
$splits{[split /;/]->[1]} = '';

is it correct?

This is syntactically correct. But then again see my other post for a
cmt on this line...


Michele
 
A

A. Sinan Unur

if(my @fields = /^\s*(\d+)\s+(\w+)\s+(\d+)\s+(\d+)\s*$/) {

Actually, that should be

if((my @fields = /^\s*(\d+)\s+(\w+)\s+(\d+)\s+(\d+)\s*$/) == 4) {

Sorry, late night post.

Sinan.
 
A

A. Sinan Unur

sorry, I forgot to mention that the data files are semicolon separated
file

Well, it looks like you should also read the posting guidelines posted here
frequently. The code you posted was not runnable and the data you posted
was not real. That is not nice.
print $out "@{[ join ';', @fields ]}\n";
} else {
warn "Cannot open $fields[1].csv: $!";

you don't close the open filehandles. Is this ok?

THe original code was:
if(open my $out, '>>', "$fields[1].csv") {
print $out "@{[ join ';', @fields ]}\n";

I know Michele has already responded to this but here's my two cents.

The crucial part is that the file is opened using open my $out, i.e. the
scope of $out is limited to the if-block. $out is a lexical filehandle.
Lexical filehandles are automatically closed upon going out of scope. On
the other hand, you can also explicitly close them. In fact, that would be
the only way to catch a failure on close.

Sinan.
 
M

Michele Dondi

open my $fh, '>', $m or
die "Can't write to `$_': $!\n";

Sorry, this should be

open my $fh, '>', $m or
die "Can't write to `$m': $!\n";

of course.


Hope there are no more typos left,
Michele
--
#!/usr/bin/perl -lp
BEGIN{*ARGV=do{open $_,q,<,,\$/;$_}}s z^z seek DATA,11,$[;($,
=ucfirst<DATA>)=~s x .*x q^~ZEX69l^^q,^2$;][@,xe.$, zex,s e1e
q 1~BEER XX1^q~4761rA67thb ~eex ,s aba m,P..,,substr$&,$.,age
__END__
 
A

A. Sinan Unur

open my $fh, '>', $m or
die "Can't write to `$m': $!\n";

of course.


Hope there are no more typos left,

Strictly speaking, not a typo, but I am going to suggest dropping the \n
from the error message.

Sinan.
 
M

Michele Dondi

open my $fh, '>', $m or
die "Can't write to `$m': $!\n"; [snip]
Hope there are no more typos left,

Strictly speaking, not a typo, but I am going to suggest dropping the \n
from the error message.

Hehe! Opinions tend to vary here... IMHO the user should not be
interested in the additional info that omitting \n supplies, and I
find that generally this is the case. Well in this case, he/she may be
interested in the line of input that triggered it, but hopefully
knowing "which $m" is the guilty one should be enough. OTOH you should
have noticed that my code contained also a \n-less warn() because in
that case it seemed to mo more meaningful to do so...


Michele
 
A

Abhinav

Michele said:
open my $fh, '>', $m or
die "Can't write to `$m': $!\n";
[snip]
Hope there are no more typos left,

Strictly speaking, not a typo, but I am going to suggest dropping the \n
from the error message.

Hehe! Opinions tend to vary here... IMHO the user should not be
interested in the additional info that omitting \n supplies, and I
find that generally this is the case. Well in this case, he/she may be
interested in the line of input that triggered it, but hopefully
knowing "which $m" is the guilty one should be enough. OTOH you should
have noticed that my code contained also a \n-less warn() because in
that case it seemed to mo more meaningful to do so...

That was interesting behaviour(for me..). Where can I find more about this ?

Regards
Abhinav
 
T

Tad McClellan

Abhinav said:
That was interesting behaviour(for me..). Where can I find more about this ?


If you are interested in the die() function, an offbeat place to
look might be the documentation for the die() function...

perldoc -f die

Please stop asking hundreds of people around the world to read
the docs to you, simply read them yourself and post only if you
still have questions after that.
 
A

Abhinav

Tad McClellan wrote:
[SNIP]
Please stop asking hundreds of people around the world to read
the docs to you, simply read them yourself and post only if you
still have questions after that.

I am sorry I asked an obviously inane question like that. Won't happen again.

Thanks
Abhinav

--
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top