19:50 <@Petruchio> Right now I'm inclined to code up a subroutine to overload
chomp, so that it'll chomp every scalar value it finds
recursively throughout a nested data structure.
I could not refrain myself from coding it immediately, so here it is :)
Update (200112202209+0100) It _does_ work, and doesn't use the outer $_. The line containing "#### <<< :-)" explains why. (for-modifier). merlyn was right about this not being easy to maintain. Sorry about that, let's just hope it doesn't need maintenance, then.
Update (200112211546+0100) gbarr uses defined() in his not-recursive version. I should have done so too, so I fixed that mistake. Also made it work with references to references.
sub mychomp; # Needed so mychomp can be used without parens
# from within mychomp
sub mychomp {
ref eq 'ARRAY' ? do { mychomp $_ for @$_ } :
ref eq 'HASH' ? do { mychomp $_ for values %$_ } :
ref eq 'REF' ? do { mychomp $$_ } :
ref eq 'SCALAR' ? eval { defined && chomp $$_ } :
ref || defined && chomp for @_ #### <<< :-)
}
# Useful stuff ends here :)
# Testing stuff starts here :)
$foo = "scalar\n";
@foo = (["first\n", "second\n", "third\n"], [[ "FIRST\n", "SECOND\n",
+"THIRD\n"],
[{xyzzy => "1st\n"}],{ xyzzy => "1<sup>st</sup>\n"} ],
"Just testing\n", \ $foo, \ \ \ $foo, \ [ "Testing :)\n" ],
[[[[[[[[[[[[[[[[[ "DEEEEEPER!\n" ]]]]]]]]]]]]]]]]]
);
mychomp @foo;
use Data::Dumper;
print Data::Dumper->Dump(\@foo);
# oh, and $foo is chomped too, of course
Re: chomp any data structure recursively
by gbarr (Monk) on Dec 21, 2001 at 19:11 UTC
|
I thought I would comment because not one of the solutions given handle a reference to a reference. So here is my non-recursive solution.
sub mychomp {
while (@_) {
for (shift) {
push @_, grep {
ref || eval { defined && chomp; 0 };
} ref eq 'ARRAY' ? @$_ :
ref eq 'HASH' ? values %$_ :
ref eq 'SCALAR' ? $$_ :
ref eq 'REF' ? $$$_ :
$_
}
}
}
Of course even this is not complete as there could be a reference to a GLOB, which could contain a SCALAR, HASH and ARRAY. But who would use those :)
| [reply] [Watch: Dir/Any] [d/l] |
|
| [reply] [Watch: Dir/Any] [d/l] |
Re: chomp any data structure recursively
by merlyn (Sage) on Dec 21, 2001 at 01:13 UTC
|
sub mychomp {
while (@_) {
eval { chomp $_[0] }, shift, next unless ref;
(push @_, @{shift @_}), next if ref $_[0] eq 'ARRAY';
(push @_, values %{shift @_}), next if ref $_[0] eq 'HASH';
shift;
}
}
-- Randal L. Schwartz, Perl hacker
update:
I didn't claim it was a working version. Thanks for the updates in the thread. {grin}
Also, I didn't see the unusual multi-line backwards-for in the original code, so it appears to be less buggy than I thought. {sigh} | [reply] [Watch: Dir/Any] [d/l] |
|
I think your version is butchering array references, and it
doesn't handle scalar references. I think this works:
sub mychomp {
while (@_) {
for (shift) {
ref or (eval { chomp if defined }, last);
ref eq 'SCALAR' and (eval { chomp $$_ if defined $$_ }, last);
ref eq 'ARRAY' and (do { push @_, map \$_, @$_ }, last);
ref eq 'HASH' and (do { push @_, map \$_, values %$_ }, last);
}
}
}
Question, though, why are we eval'ing the scalar chomps?
chomp warns on undef, but does it fail under some condition? (update: I think I answered my own question...its
for constant values which can't be chomped). | [reply] [Watch: Dir/Any] [d/l] |
|
Errr, yours just happens not to work.
use Data::Dumper;
sub mychomp {
while (@_) {
eval {chomp $_[0] }, shift, next unless ref ;
(push @_, @{shift @_}), next if ref $_[0] eq 'ARRAY';
(push @_, values %{shift @_}), next if ref $_[0] eq 'HASH';
shift;
}
}
my $foo = "scalar\n";
my @foo = (
[
"bar\n", "foo\n", "xyzzy\n",
{ blaat => "hee hee\n", hihi => "hoho\n" }
],
{qw(a b c d e f)}, "w00t\n", \$foo, \ "read-only\n"
);
mychomp(@foo);
print Dumper(\@foo);
__END__
$VAR1 = [
'ARRAY(0x80f3764)',
'HASH(0x81495a8)',
'w00t',
'SCALAR(0x8131fe8)',
'SCALAR(0x813e78c)'
];
| [reply] [Watch: Dir/Any] [d/l] |
|
Which $_ is the outer one?
The refs should see the values of @_. I can't think of a reason why they wouldn't (help me out here :)
In short, this is the pseudocode:
sub mychomp {
for (@_){
$_ is iterable && mychomp it
|| $_ is a scalar ref && try to chomp its scalar
|| $_ is not any other reference && chomp it
}
}
I'd be quite surprised my code works with many different structures if it's bugged.
Could you please give an example of what could go wrong? (of course accompanied by an explanation :)
Anyway, thanks for pointing out that it's bugged.
2;0 juerd@ouranos:~$ perl -e'undef christmas'
Segmentation fault
2;139 juerd@ouranos:~$
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
Looking at just this part:
sub mychomp {
ref eq 'ARRAY' ...
That's ref of $_, which you have not yet set up, so it's the outer $_ from the caller. Luckily, you didn't test your subroutine with
something that needed ref-ARRAY treatment as an argument. {grin}.
-- Randal L. Schwartz, Perl hacker | [reply] [Watch: Dir/Any] [d/l] |
|
|
|
| [reply] [Watch: Dir/Any] |
|
Well, then, he doesn't deserve a best node of the day award
for this one, but to be fair, he did acknowlege one (update: now both) of his mistakes, and
all I did was take his idea and "fix" it (update: and gbarr just blew mine away :), so although it
was buggy starting out, it was an interesting idea to begin with, and I
don't begrudge him a few XP for that (as if I cared
seriously about
XP at all)...
If someone posts a "you blew it" reply, I'd expect a
followup "Hey, you're right" and maybe a fix (depending
on time available -- many of us are busy, you know), but
if someone (e.g., me) posts a fix, then what's the point
in replying to that, especially if you're busy?
| [reply] [Watch: Dir/Any] |
|
|