[18567] in Perl-Users-Digest

home help back first fref pref prev next nref lref last post

Perl-Users Digest, Issue: 735 Volume: 10

daemon@ATHENA.MIT.EDU (Perl-Users Digest)
Sat Apr 21 14:06:08 2001

Date: Sat, 21 Apr 2001 11:05:13 -0700 (PDT)
From: Perl-Users Digest <Perl-Users-Request@ruby.OCE.ORST.EDU>
To: Perl-Users@ruby.OCE.ORST.EDU (Perl-Users Digest)
Message-Id: <987876312-v10-i735@ruby.oce.orst.edu>
Content-Type: text

Perl-Users Digest           Sat, 21 Apr 2001     Volume: 10 Number: 735

Today's topics:
    Re: 'Do', config files and strict <mnm@mnm.com>
        Binary (or hex?) to number and back <dwb1@home.com>
    Re: Binary (or hex?) to number and back <bart.lateur@skynet.be>
    Re: Binary (or hex?) to number and back <dwb1@home.com>
    Re: Binary (or hex?) to number and back nobull@mail.com
    Re: Binary (or hex?) to number and back (echo 'Rudolf Polzer'>/dev/null)
    Re: Extracting Data  From a 10,000 - 4-Line Structure F <joe+usenet@sunstarsys.com>
    Re: Extracting Data  From a 10,000 - 4-Line Structure F (Tad McClellan)
    Re: Extracting Data  From a 10,000 - 4-Line Structure F (Anno Siegel)
        Getting character codes <peter.reid2000@ntlworld.com>
    Re: Getting character codes <katz@underlevel.net>
    Re: Getting character codes (Anno Siegel)
    Re: Infinate loop (echo 'Rudolf Polzer'>/dev/null)
    Re: Infinate loop (Anno Siegel)
    Re: Infinate loop <scotty99@earthlink.net>
    Re: Infinate loop (Anno Siegel)
    Re: Infinate loop (echo 'Rudolf Polzer'>/dev/null)
    Re: Infinate loop (Tad McClellan)
    Re: Is it a hash or not? <glenn@surveystar.com>
    Re: Is it a hash or not? (Anno Siegel)
    Re: Is it a hash or not? <uri@sysarch.com>
    Re: Is it a hash or not? nobull@mail.com
    Re: logic programming in perl (Anno Siegel)
        Digest Administrivia (Last modified: 6 Apr 01) (Perl-Users-Digest Admin)

----------------------------------------------------------------------

Date: Sat, 21 Apr 2001 02:16:25 -0700
From: "Matt" <mnm@mnm.com>
Subject: Re: 'Do', config files and strict
Message-Id: <9bs1b4$fi7$1@plutonium.btinternet.com>

> Recipe 8.16 in the Perl Cookbook says that you can make a config file
> by using do to pull in a file of raw perl.  I thought I'd do this for
> a small script I'm writing to format some html seeing as I'm the only
> person who'll be using it.  However, it's behaving a bit oddly.
>
> In the main script I go:
>
> do 'links.conf';
>
> Links.conf contains code which looks like this:
>
> %links = ( link1 => 'A link', link2 => 'Another link');
>
> It works, but it behaves strangely.
>
> If in the main script I use strict it complains about %links.  If,
> however, I declare it 'my %links', the do does not pull in the hash
> properly and %links is undefined.
>
> Why not?  How can I do this so that strict doesn't complain?
>
> I don't understand.
>
> Thanks
>
> Paul

I asked this the other day...

"Tad McClellan" <tadmc@augustmail.com> wrote in message
news:slrn9dutl5.40i.tadmc@tadmc26.august.net...
> Matt <mnm@mnm.com> wrote:
> >If I use this
> >
> >use strict;
> >$0 =~ s:\\:/:g;
> >my $root = $1 if ($0 =~ /(.*)\/[^\/]+/);
> >require "$root/inc/global.pl";
> >
> >Then try to print a var created in the global.pl file I get the "Global
> >symbol bla requires..." errors message. Can you get round this?
>
>
> Yes.
>
> Look up the message:
>
>    perldoc perldiag
>
>
> ---------------
> =item Global symbol "%s" requires explicit package name
>
> (F) You've said "use strict vars", which indicates that all variables
> must either be lexically scoped (using "my"), declared beforehand using
> "our", or explicitly qualified to say which package the global variable
> is in (using "::").
> ---------------
>
>
> If it requires an explicit package name, then provide an explicit
> package name.
>
>
> --
>     Tad McClellan                          SGML consulting
>     tadmc@augustmail.com                   Perl programming
>     Fort Worth, Texas

I use our ($...) and that worked.






------------------------------

Date: Sat, 21 Apr 2001 14:52:33 GMT
From: "Daniel W. Burke" <dwb1@home.com>
Subject: Binary (or hex?) to number and back
Message-Id: <Pine.LNX.4.20.0104211057410.16097-100000@ethyl.addictmud.org>


Hello,


I'm trying to read a file generated by a C program... what I'm ending up with
is strings like "^EA" (2 characters, a ctrl-E and an A).  I know without a
doubt that that is supposed to be a 2-byte number.  How can I get that number?
and how can I covert that number back to that 2-character string to be written
back to the file if the value changes?

In case you're wondering, this program is a perl script instead of another
C program because it's quicker to develop the database interaction required
(except for this problem of course).

Thanks,
Dan.




------------------------------

Date: Sat, 21 Apr 2001 15:09:22 GMT
From: Bart Lateur <bart.lateur@skynet.be>
Subject: Re: Binary (or hex?) to number and back
Message-Id: <kh83etcgm0t3lvmmm9v6dhcicd492hccsu@4ax.com>

Daniel W. Burke wrote:

>I'm trying to read a file generated by a C program... what I'm ending up with
>is strings like "^EA" (2 characters, a ctrl-E and an A).  I know without a
>doubt that that is supposed to be a 2-byte number.  How can I get that number?

unpack(). Assuming this is an integer, either use 'v' for little endian
and 'n' for big endian; or 's' for native format.

>and how can I covert that number back to that 2-character string to be written
>back to the file if the value changes?

pack(). Same template.

	$packed = pack 'v', 12345;
	print "Length packed = " . length($packed) . "\n";
	print unpack 'v', $packed;
-->
	Length packed = 2
	12345

-- 
	Bart.


------------------------------

Date: Sat, 21 Apr 2001 15:17:58 GMT
From: "Daniel W. Burke" <dwb1@home.com>
Subject: Re: Binary (or hex?) to number and back
Message-Id: <Pine.LNX.4.20.0104211120520.16114-100000@ethyl.addictmud.org>

On Sat, 21 Apr 2001, Bart Lateur wrote:

> Daniel W. Burke wrote:
> 
> >I'm trying to read a file generated by a C program... what I'm ending up with
> >is strings like "^EA" (2 characters, a ctrl-E and an A).  I know without a
>
> unpack(). Assuming this is an integer, either use 'v' for little endian
> and 'n' for big endian; or 's' for native format.
> 
> >and how can I covert that number back to that 2-character string to be
> 
> pack(). Same template.
> 
> 	$packed = pack 'v', 12345;
> 	print "Length packed = " . length($packed) . "\n";
> 	print unpack 'v', $packed;
> -->
> 	Length packed = 2
> 	12345
> 
> -- 

Ah!  Hm... for some reason, I have to do this to get the numeric value I
expect:

$num = unpack('s', reverse $field);

Without the 'reverse' call, I get a bad value... I wonder if that's something
that I'm not doing right with the perl script, or the C program is saving 
funky...

Dan.





------------------------------

Date: 21 Apr 2001 16:06:56 +0100
From: nobull@mail.com
Subject: Re: Binary (or hex?) to number and back
Message-Id: <u9elumb8bz.fsf@wcl-l.bham.ac.uk>

"Daniel W. Burke" <dwb1@home.com> writes:

> I'm trying to read a file generated by a C program... what I'm ending up with
> is strings like "^EA" (2 characters, a ctrl-E and an A).  I know without a
> doubt that that is supposed to be a 2-byte number.  How can I get
> that number?

unpack() it.

> and how can I covert that number back to that 2-character string to be written
> back to the file if the value changes?

pack() it.

-- 
     \\   ( )
  .  _\\__[oo
 .__/  \\ /\@
 .  l___\\
  # ll  l\\
 ###LL  LL\\


------------------------------

Date: Sat, 21 Apr 2001 17:43:56 +0200
From: rpolzer@www42.t-offline.de (echo 'Rudolf Polzer'>/dev/null)
Subject: Re: Binary (or hex?) to number and back
Message-Id: <slrn9e3als.ppd.rpolzer@www42.t-offline.de>

Daniel W. Burke <dwb1@home.com> wrote:
> On Sat, 21 Apr 2001, Bart Lateur wrote:
> 
> > Daniel W. Burke wrote:
> > 
> > >I'm trying to read a file generated by a C program... what I'm ending up with
> > >is strings like "^EA" (2 characters, a ctrl-E and an A).  I know without a
> >
> > unpack(). Assuming this is an integer, either use 'v' for little endian
> > and 'n' for big endian; or 's' for native format.
> > 
> > >and how can I covert that number back to that 2-character string to be
> > 
> > pack(). Same template.
> > 
> > 	$packed = pack 'v', 12345;
> > 	print "Length packed = " . length($packed) . "\n";
> > 	print unpack 'v', $packed;
> > -->
> > 	Length packed = 2
> > 	12345
> > 
> > -- 
> 
> Ah!  Hm... for some reason, I have to do this to get the numeric value I
> expect:
> 
> $num = unpack('s', reverse $field);
> 
> Without the 'reverse' call, I get a bad value... I wonder if that's something
> that I'm not doing right with the perl script, or the C program is saving 
> funky...

This is exactly the difference between v and n.


-- 
#!/usr/bin/perl -W -- WARNING: This will print 22,307 bytes! <strictsafe!>
use strict;for(my$y=-1;$y<1;$y+=.1){for(my$x=-1.9;$x<.4;$x+=.03){print'+';
my$X=my$Y=0;for(0..99){($X,$Y)=($X*$X-$Y*$Y+$x,2*$X*$Y+$y);print"\b "if$X*
$X+$Y*$Y>9;}}print"\n"};print''.reverse"\nHPAJ \a!rezloP .R yb torblednaM"


------------------------------

Date: 21 Apr 2001 09:43:35 -0400
From: Joe Schaefer <joe+usenet@sunstarsys.com>
Subject: Re: Extracting Data  From a 10,000 - 4-Line Structure File
Message-Id: <m3pue6v054.fsf@mumonkan.sunstarsys.com>

"biG" <ofirb1@netvision.net.il> writes:

> I have a file contains 10,000 staff's records (details), in a 4-line
> structure:
> First line: First & Last Name
> Second line:  Phone extension
> Third line: Room Number
> Four line: Job title
> 
> How do I build a script to parse this file, extracting the details (each
> line to a separate field/variable), and joining second & third lines to one
> line?

It somewhat depends on how 2 records are separated within the file.
If they are separated by an additional newline, like this

George Bush
1-800-oil-well
Oval Office
CEO

Al Gore
1-800-IH8-chad
Room 230, Columbia University
Adjunct

 ...

Then you could use paragraph mode to parse it:

  local $/ = ''; # paragraph mode - see perlvar for details

  while(<FILE>) {
    my %data;
    @data{ qw/ name tel room position / } = split /\n/;
    $data{comboline} = "$data{tel} - $data{room}";
    ...

  }


But if nothing separates the individual records, then you'll have 
to keep track of the line numbers:

  my %data;
  my @field = qw/ name tel room position /;
  my $count = 0;        # counts lines starting from 0

  LINE: while (<FILE>) {
            chomp;
            $data{ $field[$count % 4] } = $_;
            ++$count;

            goto LINE unless $count % 4 == 3;   # lines 0-3 load the hash

            $data{comboline} = "$data{tel} - $data{room}";

            ...

  } continue { undef %data }


See

  % perldoc perl
  % perldoc perlsyn
  % perldoc perldata

for details.

HTH

-- 
Joe Schaefer             "Life is just one damn thing after another."
                                               --Mark Twain


------------------------------

Date: Sat, 21 Apr 2001 10:24:07 -0400
From: tadmc@augustmail.com (Tad McClellan)
Subject: Re: Extracting Data  From a 10,000 - 4-Line Structure File
Message-Id: <slrn9e3607.9cg.tadmc@tadmc26.august.net>

biG <ofirb1@netvision.net.il> wrote:
>
>I have a file contains 10,000 staff's records (details), in a 4-line
>structure:
>First line: First & Last Name
>Second line:  Phone extension
>Third line: Room Number
>Four line: Job title
>
>How do I build a script to parse this file, 


If it was me, I would first insert record separator lines and use
the $/ special variable (see perlvar.pod) to read one record at
a time.

But if you are guaranteed that the number of lines in the file is
a multiple of four, then you can just do 4 reads for each record.

>extracting the details (each
>line to a separate field/variable), and joining second & third lines to one
>line?
>I know it's not a short one, 


Seems like about 7 lines to do the real work. I'd call that short :-)

--------------------------
#!/usr/bin/perl -w
use strict;

while ( my $name = <DATA> ) {
   chomp $name;

   my $phone = <DATA> . <DATA>;   # 2nd and 3rd lines
   $phone =~ s/\n//;              # strip the interior newline
   chomp $phone;

   my $title = <DATA>;            # 4th line
   chomp $title;

   print "name '$name'\n";
   print "phone '$phone'\n";
   print "title '$title'\n";
}

__DATA__
First line: First & Last Name
Second line:  Phone extension
Third line: Room Number
Four line: Job title
First line: First & Last Name
Second line:  Phone extension
Third line: Room Number
Four line: Job title
First line: First & Last Name
Second line:  Phone extension
Third line: Room Number
Four line: Job title
--------------------------


>but I beg for even the basics, so I could learn
>from it.


Good luck!


-- 
    Tad McClellan                          SGML consulting
    tadmc@augustmail.com                   Perl programming
    Fort Worth, Texas


------------------------------

Date: 21 Apr 2001 17:46:10 GMT
From: anno4000@lublin.zrz.tu-berlin.de (Anno Siegel)
Subject: Re: Extracting Data  From a 10,000 - 4-Line Structure File
Message-Id: <9bsh12$ltd$1@mamenchi.zrz.TU-Berlin.DE>

According to Joe Schaefer  <joe+usenet@sunstarsys.com>:
> "biG" <ofirb1@netvision.net.il> writes:
> 
> > I have a file contains 10,000 staff's records (details), in a 4-line
> > structure:
> > First line: First & Last Name
> > Second line:  Phone extension
> > Third line: Room Number
> > Four line: Job title
> > 
> > How do I build a script to parse this file, extracting the details (each
> > line to a separate field/variable), and joining second & third lines to one
> > line?
> 
> It somewhat depends on how 2 records are separated within the file.

[...]
 
> But if nothing separates the individual records, then you'll have 
> to keep track of the line numbers:
> 
>   my %data;
>   my @field = qw/ name tel room position /;
>   my $count = 0;        # counts lines starting from 0
> 
>   LINE: while (<FILE>) {
>             chomp;
>             $data{ $field[$count % 4] } = $_;
>             ++$count;
> 
>             goto LINE unless $count % 4 == 3;   # lines 0-3 load the hash
> 
>             $data{comboline} = "$data{tel} - $data{room}";
> 
>             ...
> 
>   } continue { undef %data }

This looks more complicated than it has to be.  Why don't you read
a quadruple of lines directly, like so:

    my $premature;
    RECORD: while ( 1 ) {
        my %data;
        for my $field ( qw/ name tel room position / ) {
            last RECORD if eof DATA;
            $premature = 1;
            chomp( $data{ $field} = <DATA>);
        }
        $premature = 0;
        $data{ comboline} = "$data{tel} - $data{room}";
    #   ...
    }

This processes one record at a time, as god intended, at the cost
of a somewhat irregular loop control.  I included the $premature
variable for error checking because its placement (well, the
placement of the "$premature = 1" statement) is slightly tricky.

Anno


------------------------------

Date: Sat, 21 Apr 2001 17:42:54 GMT
From: Peter Reid <peter.reid2000@ntlworld.com>
Subject: Getting character codes
Message-Id: <1103_987874974@default>

Does anyone know how to get the character code of a letter (eg X is 88) and also how to get a letter from its code ????


Peter Reid



------------------------------

Date: 21 Apr 2001 13:59:41 -0400
From: Jordan Katz <katz@underlevel.net>
Subject: Re: Getting character codes
Message-Id: <m3r8ymjfqq.fsf@underlevel.underlevel.net>

Peter Reid <peter.reid2000@ntlworld.com> writes:

> Does anyone know how to get the character code of a letter (eg X is
> 88) and also how to get a letter from its code ????

code to letter: perl -e 'print chr(88);'
letter to code: perl -e 'print ord(X);'
-- 
Jordan Katz <katz@underlevel.net>  |  Mind the gap


------------------------------

Date: 21 Apr 2001 18:01:49 GMT
From: anno4000@lublin.zrz.tu-berlin.de (Anno Siegel)
Subject: Re: Getting character codes
Message-Id: <9bshud$ltd$2@mamenchi.zrz.TU-Berlin.DE>

According to Peter Reid  <peter.reid2000@ntlworld.com>:
> Does anyone know how to get the character code of a letter (eg X is 88)
> and also how to get a letter from its code ????

ord() and chr().

Anno


------------------------------

Date: Sat, 21 Apr 2001 16:13:56 +0200
From: rpolzer@www42.t-offline.de (echo 'Rudolf Polzer'>/dev/null)
Subject: Re: Infinate loop
Message-Id: <slrn9e35d4.b72.rpolzer@www42.t-offline.de>

Ed <e.c.fowler@ncl.ac.uk> wrote:
> Hello, I am having problems deleting the duplicates from my Ndbm file. 
> Is it becuse I can't do it this way (accessing same hash nested and
> deleting entry)?  This code just gives an infinite loop!  Please help!
> Ed
> 
> my $key;
> my $value;
> my %dbm_hash;
> tie(%dbm_hash, 'NDBM_File',
> '/ncl/www/people/e.c.fowler/cgi-bin/Prot2App',O_CREAT|O_RDWR, 0600) or
> die "unableto open file: $!";   
> #Step through entry by entry
> while (($key, $value) = each %dbm_hash)
> {
>    my $key2;
>    my $value2;
>    #Step through again (i.e. comparing entries)
>    while (($key2, $value2) = each %dbm_hash)
                               ^^^^^^^^^^^^^^
>    {
>       #Check each entry against every other entry
>       if($value eq $value2)
>       {
>          delete $dbm_hash{$key2};
           ^^^^^^^^^^^^^^^^
>       }
>    }
>  
> }
> untie (%dbm_hash);

You may not modify/add/delete keys of a hash you are iterating with 
'each': perldoc -f each.

But I wonder why it creates an infinite loop; I would expect a loop 
that takes VERY LONG but it should do what you want.

And to delete these: I would recomment pushing the keys you want to 
remove into an array and do a

for (@to_be_deleted)
{
 delete $dbm_hash{$_};
}

afterwards.

-- 
#!/usr/bin/perl -W -- WARNING: This copies a random file from
use strict;my$s;my$n=0;for # the  current  directory  to your 
(<*>){++$n;int rand$n or$s # signature  file.   Use  at  your
=$_};`cp $s ~/.signature`; # own risk! (c) 2001 Rudolf Polzer


------------------------------

Date: 21 Apr 2001 14:04:22 GMT
From: anno4000@lublin.zrz.tu-berlin.de (Anno Siegel)
Subject: Re: Infinate loop
Message-Id: <9bs416$a9s$1@mamenchi.zrz.TU-Berlin.DE>

According to Ed  <e.c.fowler@ncl.ac.uk>:
> Hello, I am having problems deleting the duplicates from my Ndbm file. 
> Is it becuse I can't do it this way (accessing same hash nested and
> deleting entry)?  This code just gives an infinite loop!  Please help!

No, you can't do it this way, as a look at the description of each()
would have shown.  Neither can you nest each-loops, nor are you
supposed to change the underlying hash while iterating over it.

When you have to select unique elements from a set, in Perl the
answer is most often: Use a hash.  In particular, use whatever you
want to uniquify as the keys of a hash, because these are unique
by construction.

To select a set of keys from a hash %h so that there is a unique value
associated with each key, just do this:

    %h = reverse %h;
    %h = reverse %h;

The first one does the work:  It builds a hash whose keys are the
values of the original, associating one of the former keys with
it.  Each of the old values appears exactly once among the keys of
this hash.  The second line restores things so that keys are keys
and values are values again.  No information is lost at this step
because we already have a 1-1 relationship.

Now, this simple idiom is only efficient for smallish hashes that
can be kept in memory.  If your DBM-tie is because of size, you may
have to tie a temporary second hash and build both reverses step by
step to achieve the same effect.  Don't forget to clear the original
before re-assigning the key/value pairs, or, better yet, build a new
one.

[code snipped]

Anno


------------------------------

Date: Sat, 21 Apr 2001 14:21:37 GMT
From: Scott <scotty99@earthlink.net>
Subject: Re: Infinate loop
Message-Id: <3AE1432C.7BBEE8FA@earthlink.net>



Ed wrote:

> Hello, I am having problems deleting the duplicates from my Ndbm file.
> Is it becuse I can't do it this way (accessing same hash nested and
> deleting entry)?  This code just gives an infinite loop!  Please help!
> Ed
>
> my $key;
> my $value;
> my %dbm_hash;
> tie(%dbm_hash, 'NDBM_File',
> '/ncl/www/people/e.c.fowler/cgi-bin/Prot2App',O_CREAT|O_RDWR, 0600) or
> die "unableto open file: $!";
> #Step through entry by entry
> while (($key, $value) = each %dbm_hash)
> {
>    my $key2;
>    my $value2;
>    #Step through again (i.e. comparing entries)
>    while (($key2, $value2) = each %dbm_hash)
>    {
>       #Check each entry against every other entry
>       if($value eq $value2)
>       {
>          delete $dbm_hash{$key2};
>       }
>    }
>
> }
> untie (%dbm_hash);

like the one guy said you shouldn't modify or change a hash while
iterating through it,
but depending on the size of the file I wouldn't want to slurp it in an
array either.
YOu could create a tempDBM hash (I don't know how to do this as I've only
workded with CDB files, so I am just writing pseudocode for adding items
to a DBM file)
then after that first while statement put:
TempDBM->insert($key,$value) unless $seen{$value};
$seen{$value}=1;

Scott



------------------------------

Date: 21 Apr 2001 14:23:02 GMT
From: anno4000@lublin.zrz.tu-berlin.de (Anno Siegel)
Subject: Re: Infinate loop
Message-Id: <9bs546$b6b$1@mamenchi.zrz.TU-Berlin.DE>

According to echo 'Rudolf Polzer'>/dev/null <null@durchnull.de>:
> Ed <e.c.fowler@ncl.ac.uk> wrote:
> > Hello, I am having problems deleting the duplicates from my Ndbm file. 
> > Is it becuse I can't do it this way (accessing same hash nested and
> > deleting entry)?  This code just gives an infinite loop!  Please help!
> > Ed

[code reduced to the essential]

> > while (($key, $value) = each %dbm_hash) {
> >    while (($key2, $value2) = each %dbm_hash) {
       }
    }

> You may not modify/add/delete keys of a hash you are iterating with 
> 'each': perldoc -f each.

Correct.

> But I wonder why it creates an infinite loop; I would expect a loop 
> that takes VERY LONG but it should do what you want.

That's easy to explain:  each() is reset to start the hash over when
the inner loop reaches the end.  (There's only a single iterator for
each hash.)  So the outer loop will start anew - there's your infinite
loop.

> And to delete these: I would recomment pushing the keys you want to 
> remove into an array and do a
> 
> for (@to_be_deleted)
> {
>  delete $dbm_hash{$_};
> }

Bad advice.  Even if it worked (which it doesn't, as explained above),
it would result in a procedure that loops n^2 times for a hash with
n entries.  Using another hash to get the unique values does it in
linear time.

Anno


------------------------------

Date: Sat, 21 Apr 2001 16:50:31 +0200
From: rpolzer@www42.t-offline.de (echo 'Rudolf Polzer'>/dev/null)
Subject: Re: Infinate loop
Message-Id: <slrn9e37hn.i0b.rpolzer@www42.t-offline.de>

Anno Siegel <anno4000@lublin.zrz.tu-berlin.de> wrote:
> According to echo 'Rudolf Polzer'>/dev/null <null@durchnull.de>:
> > Ed <e.c.fowler@ncl.ac.uk> wrote:
> > > Hello, I am having problems deleting the duplicates from my Ndbm file. 
> > > Is it becuse I can't do it this way (accessing same hash nested and
> > > deleting entry)?  This code just gives an infinite loop!  Please help!
> > > Ed
> 
> [code reduced to the essential]
> 
> > > while (($key, $value) = each %dbm_hash) {
> > >    while (($key2, $value2) = each %dbm_hash) {
>        }
>     }
> 
> > You may not modify/add/delete keys of a hash you are iterating with 
> > 'each': perldoc -f each.
> 
> Correct.
> 
> > But I wonder why it creates an infinite loop; I would expect a loop 
> > that takes VERY LONG but it should do what you want.
> 
> That's easy to explain:  each() is reset to start the hash over when
> the inner loop reaches the end.  (There's only a single iterator for
> each hash.)  So the outer loop will start anew - there's your infinite
> loop.

Sorry... I did not see the nesting.

-- 
#!/usr/bin/perl -W -- WARNING: This copies a random file from
use strict;my$s;my$n=0;for # the  current  directory  to your 
(<*>){++$n;int rand$n or$s # signature  file.   Use  at  your
=$_};`cp $s ~/.signature`; # own risk! (c) 2001 Rudolf Polzer


------------------------------

Date: Sat, 21 Apr 2001 09:57:14 -0400
From: tadmc@augustmail.com (Tad McClellan)
Subject: Re: Infinate loop
Message-Id: <slrn9e34dq.9cg.tadmc@tadmc26.august.net>

Ed <e.c.fowler@ncl.ac.uk> wrote:

>Hello, I am having problems deleting the duplicates from my Ndbm file. 


You want to remove duplicate _values_ I guess.

If you have

   $dbm_hash{Ed} = 'comp.lang.perl.misc';
and
   $dbm_hash{Tad} = 'comp.lang.perl.misc';


Which key/value pair is to be delete()d?

How do you determine which of the keys stays and which go?


>Is it becuse I can't do it this way (accessing same hash nested and
>deleting entry)?  


Yes, you cannot do it that way.

   perldoc -f each

      "There is a single iterator for each hash, shared by all..."


>This code just gives an infinite loop!  Please help!


Can't, because you have not given enough detail about what it is
that you want to do when you find a duplicate hash value.

If you "don't care" which of the keys is deleted, you could eliminate
duplicate values by inverting the hash.

If you want the same hash with "don't care" uniquified values,
invert the hash twice, once to eliminate duplicate values (by
using them as keys) and once to get the keys back again.


   %dbm_hash = reverse %dbm_hash;  # keys become values, values become keys
   %dbm_hash = reverse %dbm_hash;  # return them to their original roles

But that is likely to be slow, especially if the hash is tied
(so maybe it _does_ matter that it is tied :-), so see below.


>my $key;
>my $value;
>my %dbm_hash;
>tie(%dbm_hash, 'NDBM_File',
>'/ncl/www/people/e.c.fowler/cgi-bin/Prot2App',O_CREAT|O_RDWR, 0600) or
>die "unableto open file: $!";   


We do not need to know that the hash is tie()d.

You should try and reduce your posted code to only what is required
to illustrate your problem.

A plain hash, initialized with some data, would have been much better.

This has the added advantage of allowing potential answerers to
run real code while developing the answer. You will get a much
better answer that way than relying only on a "code review"
rather than real, running, code.


>#Step through entry by entry
>while (($key, $value) = each %dbm_hash)
                         ^^^^^^^^^^^^^^

>{

>   while (($key2, $value2) = each %dbm_hash)
                              ^^^^^^^^^^^^^^

Oops. You have "dualing iterators". 

I dunno what behavior to expect when you do that (but under the 
circumstances, "an infinite loop" seems a reasonable guess :-).

Since changing the hash while iterating is a Bad Idea (unless MJD
never pays out his $50), simply collect a list of keys to be deleted
while iterating, then delete() them after you've finished iterating:

----------------
my %seen;
my @keys;
while ( my($key, $value) = each %dbm_hash ) {
   push @keys, $key if $seen{$value}++;
}

delete $dbm_hash{$_} foreach @keys;
----------------


-- 
    Tad McClellan                          SGML consulting
    tadmc@augustmail.com                   Perl programming
    Fort Worth, Texas


------------------------------

Date: Sat, 21 Apr 2001 13:01:39 GMT
From: Glenn Davis <glenn@surveystar.com>
Subject: Re: Is it a hash or not?
Message-Id: <3AE1848A.3A7F63D4@surveystar.com>

Glenn Davis wrote:
 ...

Let's try this again....  Trying to use ref() here.  Based on what I've just
learned, I understand that if I say
        ref($listname)   # $listname must be a reference
but if I define it as a reference to a hash
        ref(\%$listname) # it returns HASH regardless of whether or not it
really is

here's my complete test program...

@list1=('a', 'b', 'c');              # list1 is an array
%list2=(1=>'a', 2=>'b', 3=>'c');     # list2 is a hash

$listname="list1";  # the list's name only as a string

$type=ref(\%$listname);            # a reference to the item as a hash
print "$listname is a... $type\n";   #   ...shows a HASH regardless
$type=ref(\@$listname);            # a reference to the same item as an
array
print "$listname is a... $type\n";   #   ...shows a ARRAY regardless

$listname="list2";  # the list's name only as a string

$type=ref(\%$listname);            # a reference to the item as a hash
print "$listname is a... $type\n";   #   ...shows a HASH regardless
$type=ref(\@$listname);            # a reference to the same item as an
array
print "$listname is a... $type\n";   #   ...shows a ARRAY regardless





------------------------------

Date: 21 Apr 2001 15:48:07 GMT
From: anno4000@lublin.zrz.tu-berlin.de (Anno Siegel)
Subject: Re: Is it a hash or not?
Message-Id: <9bsa3n$ep9$1@mamenchi.zrz.TU-Berlin.DE>

According to Bart Lateur  <bart.lateur@skynet.be>:
> Glenn Davis wrote:
> 
> >I am using...
> >
> >         if (keys(%$listname)) {
> >           $hash=1;
> >           }
> >        if ($hash) ...
> >
> >...which seems to work fine in my testing, but I wonder whether this
> >will always work, or if there are any risks of using the % syntax in
> >situations where $listname is not a hash.
> 
> Yup. If it's not a hash ref, then this will croak.

Only under strictures, and I have reason to believe the OP isn't running
strict 'refs'.  Then it will use the contents of $listname (estne nomen
omen?) for a symref and act accordingly, i.e. return 0 unless a hash
of that name was initialized elsewhere.

> Check if ref($hash) is "HASH" (only of not blessed), if $ref as a string
> contains "=HASH", or, better still, use the UNIVERSAL method isa:
> 
> 	print UNIVERSAL::isa($ref, "HASH")?'y':'n';

The elevated ranks of the Perl Order tend to overlook how close the
sin of symrefs is to the ordinary being.

Anno


------------------------------

Date: Sat, 21 Apr 2001 15:50:23 GMT
From: Uri Guttman <uri@sysarch.com>
Subject: Re: Is it a hash or not?
Message-Id: <x77l0ejlq3.fsf@home.sysarch.com>

>>>>> "GD" == Glenn Davis <glenn@surveystar.com> writes:

i've been watching this thread and i was suspicious.


  GD> here's my complete test program...

  GD> $listname="list1";  # the list's name only as a string

hmm, a major clue!

  GD> $type=ref(\%$listname);            # a reference to the item as a hash
  GD> print "$listname is a... $type\n";   #   ...shows a HASH regardless
  GD> $type=ref(\@$listname);            # a reference to the same item as an
  GD> array
  GD> print "$listname is a... $type\n";   #   ...shows a ARRAY regardless

proof! he is trying to use symbolic refs. no wonder he got bamboozled by
ref. and i am shocked (did i say SHOCKED!) to find that
gambling^Wsymrefs were being attempted here and no one jumped on it.

don't use symrefs is the proper answer. ref on a string name returns
false. it only returns a ref type on a real reference.

	$type=ref(\%$listname);  # EVIL!!!

that will always return HASH since you MADE it a hash. you are refering
to the global hash named %list1

the same is true for the array version. you can have a hash AND an array
named list1 so you can't tell them apart by using symrefs. this is
another one of the many reasons why you should NOT use symrefs. 

so, stop trying to do that and stick to hard references and the ref
function. it will do what you want.

uri

-- 
Uri Guttman  ---------  uri@sysarch.com  ----------  http://www.sysarch.com
SYStems ARCHitecture and Stem Development ------ http://www.stemsystems.com
Learn Advanced Object Oriented Perl from Damian Conway - Boston, July 10-11
Class and Registration info:     http://www.sysarch.com/perl/OOP_class.html


------------------------------

Date: 21 Apr 2001 17:34:46 +0100
From: nobull@mail.com
Subject: Re: Is it a hash or not?
Message-Id: <u9bspqb49l.fsf@wcl-l.bham.ac.uk>

Glenn Davis <glenn@surveystar.com> writes:

> Let's try this again....  Trying to use ref() here.  Based on what I've just
> learned, I understand that if I say
>         ref($listname)   # $listname must be a reference but if I define it as a reference to a hash

No, if $listname is not a reference the ref() simply returns undef.

>         ref(\%$listname) # it returns HASH regardless of whether or not it really is

On would expect that that must always die or return 'HASH'. (Unless
%$listname is a blessed hash, in which case it returns the class
name).

$listname='list1';
print ref(\%$listname); # prints HASH

bless \%list1, 'FOO';
print ref(\%$listname); # prints FOO

$listname=\%list1;
print ref(\%$listname); # prints FOO
print ref(\@$listname); # dies 'Not an ARRAY reference'

$listname = \$scalar;
print ref(\%$listname); # dies 'Not a HASH reference'


> $listname="list1";  # the list's name only as a string
> 
> $type=ref(\%$listname);            # a reference to the item as a hash
> print "$listname is a... $type\n";   #   ...shows a HASH regardless
> $type=ref(\@$listname);            # a reference to the same item as array
> print "$listname is a... $type\n";   #   ...shows a ARRAY regardless

Here $listname is a _symbolic_ reference.  Symbolic references are, in
effect, always references to symbol table entries (typeglobs) and can
be derefernced to refer to the GLOB as a whole _or_ any of the
individual typed components of that GLOB (hash, array, scalar,
filehandle, subroutine...).

The every act of dereferencing the string "list1" in an array-ref
context causes the global variable @list1 to come into being.

Everything above is doing exactly the right thing.

Now _here_ is the odd bit:

my @array;
my $arrayref = \@array;
print ref (\%$arrayref); # Prints ARRAY

What one nieavely would exect to happen above is a 'Not a HASH
reference' error.  This does not happen because array references can
legitimately be used as hash references.

See perlref/"Pseudo-hashes: Using an array as a hash"

-- 
     \\   ( )
  .  _\\__[oo
 .__/  \\ /\@
 .  l___\\
  # ll  l\\
 ###LL  LL\\


------------------------------

Date: 21 Apr 2001 13:27:30 GMT
From: anno4000@lublin.zrz.tu-berlin.de (Anno Siegel)
Subject: Re: logic programming in perl
Message-Id: <9bs1s2$8n3$1@mamenchi.zrz.TU-Berlin.DE>

[jeopardy posting corrected. don't do that]

According to Gregory Toomey <gtoomey@usa.net>:

> > I have heard that Perl can be written in different programming styles..
> > from the standard syntax to something that has the look and feel of a
> > functional language... but what I want to know is can it be used in a
> > logic programming style?  I've searched the web and can't find anything
> > on it, but that doesn't mean it can't be done!

> For logic programming (a la Prolog) you need backward chaining and
> unification.

That's a rather extensive concept of logic programming.  In a more
modest way, you can indeed use a logic style of programming with Perl,
as you can with any language that supports shortcut boolean expressions.

A parser (for a suitable grammar) might be implemented as a set of
routines that recognize terminals, meaning they return true (consuming
text) if a certain token is there and return false (consuming nothing)
if it isn't.  In this setup, to say that a factor is either a literal
(a terminal), or a variable (another terminal), or an expression (a non-
terminal defined elsewhere) in parentheses (terminals), you could say:

    sub factor () {
        literal or variable or 
            open_par and expression and close_par;
    }


Well, that's simplified, you may need a backtrack mechanism for a
real parser, but it shows how a logic style of programming in Perl
might look like.

Anno


------------------------------

Date: 6 Apr 2001 21:33:47 GMT (Last modified)
From: Perl-Users-Request@ruby.oce.orst.edu (Perl-Users-Digest Admin) 
Subject: Digest Administrivia (Last modified: 6 Apr 01)
Message-Id: <null>


Administrivia:

The Perl-Users Digest is a retransmission of the USENET newsgroup
comp.lang.perl.misc.  For subscription or unsubscription requests, send
the single line:

	subscribe perl-users
or:
	unsubscribe perl-users

to almanac@ruby.oce.orst.edu.  

To submit articles to comp.lang.perl.announce, send your article to
clpa@perl.com.

To request back copies (available for a week or so), send your request
to almanac@ruby.oce.orst.edu with the command "send perl-users x.y",
where x is the volume number and y is the issue number.

For other requests pertaining to the digest, send mail to
perl-users-request@ruby.oce.orst.edu. Do not waste your time or mine
sending perl questions to the -request address, I don't have time to
answer them even if I did know the answer.


------------------------------
End of Perl-Users Digest V10 Issue 735
**************************************


home help back first fref pref prev next nref lref last post