Trying to change ID value in @array

D

\Dandy\ Randy

Hi, I'm trying to replace the ID number in my @array. Each entry of
addressbook.txt has an ID number, a name and an email address separated by a
"|" in this format:

1|Robert|[email protected]
2|Gerry|[email protected]
3|Frank|[email protected]

A user simply inputs a number in a web form, then the data is passed to this
deletion script:

# Get array entries
open (ADDRESSES, "<data/addressbook.txt") or die "Can't open file: $!";
@recipients=<ADDRESSES>;
close(ADDRESSES);

# Loop to locate and delete entry based on form data
foreach $recipients(@recipients) {
($id,$name,$email)=split(/\|/,$recipients);
$count++;
if ($id eq "$form{'id'}") {
$count--;
splice(@recipients, $count, 1);
}
}

########
# Missing code here to adjust ID numbers
########

# Print the changed bata back to file
open (ADDRESSES, ">data/addressbook.txt") or die "Can't open file: $!";
print ADDRESSES @recipients;
close(ADDRESSES);

So far this script works correctly. Lets say I entered "2" into the web
form, after the script is run, addressbook.txt would now contain the
following:

1|Robert|[email protected]
3|Frank|[email protected]

Notice the ID numbers are 1 & 3 ... I would like to add another peice of
code to the above script that will change the ID number based on entries
remaining in the text file ... when the @array data gets saved back to the
text file, it would show as:

1|Robert|[email protected]
2|Frank|[email protected]

I tried this "replacement" method in the "Missing code" section but didn't
work:

foreach $recipients(@recipients) {
($id,$name,$email)=split(/\|/,$recipients);
$newid++;
$recipients =~ s/$id/$newid/g;
}

Can someone help point me in the right direction to accomplish my goal? COde
examples welcomed. Thanx everyone.

Randy
 
D

\Dandy\ Randy

"Dandy" Randy said:
Can someone help point me in the right direction to accomplish my goal? COde
examples welcomed. Thanx everyone.

Randy

I think I figured it out ... well it works, but I sure there was a better
way. I inserted the following into the missing code section:

foreach $recipients(@recipients) {
($id,$name,$email)=split(/\|/,$recipients);
$xxx++;
$recipients = "$xxx|$name|$email";
}

Randy
 
M

Mina Naguib

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Dandy" Randy said:
Hi, I'm trying to replace the ID number in my @array. Each entry of
addressbook.txt has an ID number, a name and an email address separated by a
"|" in this format:

1|Robert|[email protected]
2|Gerry|[email protected]
3|Frank|[email protected]

A user simply inputs a number in a web form, then the data is passed to this
deletion script:

# Get array entries
open (ADDRESSES, "<data/addressbook.txt") or die "Can't open file: $!";
@recipients=<ADDRESSES>;
close(ADDRESSES);

# Loop to locate and delete entry based on form data
foreach $recipients(@recipients) {
($id,$name,$email)=split(/\|/,$recipients);
$count++;
if ($id eq "$form{'id'}") {
$count--;
splice(@recipients, $count, 1);
}
}

########
# Missing code here to adjust ID numbers
########

# Print the changed bata back to file
open (ADDRESSES, ">data/addressbook.txt") or die "Can't open file: $!";
print ADDRESSES @recipients;
close(ADDRESSES);

So far this script works correctly. Lets say I entered "2" into the web
form, after the script is run, addressbook.txt would now contain the
following:

1|Robert|[email protected]
3|Frank|[email protected]

Notice the ID numbers are 1 & 3 ... I would like to add another peice of
code to the above script that will change the ID number based on entries
remaining in the text file ... when the @array data gets saved back to the
text file, it would show as:

1|Robert|[email protected]
2|Frank|[email protected]

I tried this "replacement" method in the "Missing code" section but didn't
work:

foreach $recipients(@recipients) {
($id,$name,$email)=split(/\|/,$recipients);
$newid++;
$recipients =~ s/$id/$newid/g;
}

Can someone help point me in the right direction to accomplish my goal? COde
examples welcomed. Thanx everyone.

Randy

There are several logical and technical issues with your approach.

#1. You don't seem to be doing any sanity checking on the incoming ID from the web form, this would
allow anyone who has access to reach this part of the program to delete any entry in the database.
#2. Typically, IDs assigned to a database entry should maintain uniqueness when other entries are
changed. Assume for example that in your script someone requests deletion of ID #4, then hits
refresh over and over and over. Since everyone's IDs are re-numbered after every deletion, that can
cause a malicious user to truncate your database to only 4 items !
.. . and many other scenarios.
#3. Using something like $form{id} tells me that you're not using the CGI module to parse the input.
Don't do that, see perldoc CGI

Since you haven't explained the top-level use of your database I'll assume you know what you're
doing and you really want the IDs re-numbered. Here's a quick way to do it:

$filename = "data/addressbook.txt";

#
# Read data excluding item to be deleted into @addresses
#
open (FH, $filename);
while (<FH>) {
chomp;
($id, @parts) = split(/\|/);
if ($id ne $form{id}) {
push (@addresses, [@parts]);
}
}
close (FH);

#
# Write the data back into the file
#
open (FH, ">$filename");
for $index (0..$#addresses) {
print FH $index+1, "|", join("|", @{$addresses[$index]}), "\n";
}
close (FH);


Error-checking left out in above code for brevety.

And finally, if you do decide that re-numbering the IDs was a bad idea, then all of the above was
re-inventing the wheel, as what you're dealing with is called a text-file delimmited-database and
there are numerous well-tested modules on CPAN that allow you to easily and reliable modify such files.

Best of luck.

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQE/bMtqeS99pGMif6wRAozTAKCliiiPl26g1t0hQf++cKENGA7BuwCglsmd
ZeYn1Uu+moONDp4IGbl8L44=
=pPwq
-----END PGP SIGNATURE-----
 
C

Chief Squawtendrawpet

\"Dandy\" Randy said:
A user simply inputs a number in a web form, then the data is passed to this
deletion script:

Based on what you've told us, my inclination would be to use a hash instead
of an array to hold the recipients.
$recipients{ID_NUMBER} = [NAME, EMAIL]

Deleting a particular recipient becomes easy:
delete $recipients{$form{id}};

Then, when you write to the file, just sort the hash keys and use an
iterator to adjust the ID numbers [code not tested]:
$n = 1;
for my $k (sort {$a <=> $b} keys %recipients){
print ADDRESSES join('|', $n, @{$recipients{$k}}), "\n";
$n ++;
}

Chief S.
 
D

\Dandy\ Randy

Mina Naguib said:
And finally, if you do decide that re-numbering the IDs was a bad idea, then all of the above was
re-inventing the wheel, as what you're dealing with is called a text-file delimmited-database and
there are numerous well-tested modules on CPAN that allow you to easily
and reliable modify such files.

Mina,

Ok, good points. I have opted to not use the ID method. I am however having
a matching problem. So I have removed all of the ID numbers from the file,
leaving something like this:

Valcourt|[email protected]
Smith|[email protected]
Genry|[email protected]
Genry|[email protected]

Now the web form as two input fields ... a name field and an email field. To
remove an entry, you must EXACTLY input the correct name and email address.
Based on that input, the delete script would remove the entry.

The following is not working and I have not located a viable solution:

#################

$inputentry = "$form{'name'}|$form{'email'}";

open (ADDRESSES, "<data/addressbook.txt") or die "Can't open file: $!";
@entrys=<ADDRESSES>;
close(ADDRESSES);

foreach $entry (@entrys) {
$remove++;
if ($entry eq $inputentry) {
$remove--;
splice(@entrys, $remove, 1);
}
}

#################

I have also tried this method, but funky things happen (see text file
entires above) ... if I type "Genry" as the name and (e-mail address removed)2 as
the email, it removes the (e-mail address removed) entry instead, and leaves the
(e-mail address removed)2 entry intact:

#################

$inputentry = "$form{'name'}|$form{'email'}";

open (ADDRESSES, "<data/addressbook.txt") or die "Can't open file: $!";
@entrys=<ADDRESSES>;
close(ADDRESSES);

foreach $entry (@entrys) {
$remove++;
if ($entry =~ /$inputentry/) {
$remove--;
splice(@entrys, $remove, 1);
}
}

#################

I am at a loss. I have tried several matching operators like =~ , eq , ne ,
= , !~ , non of which are matching the $entry to the $inputentry values.
Where am I going wrong? TIA!!!!
Randy
 
K

ko

Dandy" Randy said:
Mina,

Ok, good points. I have opted to not use the ID method. I am however having
a matching problem. So I have removed all of the ID numbers from the file,
leaving something like this:

Valcourt|[email protected]
Smith|[email protected]
Genry|[email protected]
Genry|[email protected]

Now the web form as two input fields ... a name field and an email field. To
remove an entry, you must EXACTLY input the correct name and email address.
Based on that input, the delete script would remove the entry.
[snip]

$inputentry = "$form{'name'}|$form{'email'}";

Since you have chosen to join the two form fields into a string, it
might be easier to lookup via a hash:

# build lookup hash
open (ADDRESSES, 'YOUR_FILE') or die $!;
my (@entrys, %entrys) = <ADDRESSES>;
chomp foreach @entrys;
@entrys{@entrys} = ();

# remove entry, $inputentry from previous
delete $entrys{$inputentry} if exists $entrys{$inputentry};

HTH - keith
 
R

Robert TV

ko said:
Since you have chosen to join the two form fields into a string, it
might be easier to lookup via a hash:

# build lookup hash
open (ADDRESSES, 'YOUR_FILE') or die $!;
my (@entrys, %entrys) = <ADDRESSES>;
chomp foreach @entrys;
@entrys{@entrys} = ();

# remove entry, $inputentry from previous
delete $entrys{$inputentry} if exists $entrys{$inputentry};

Hi HTH, I have tried using your method as described above. In all instances,
all elements of the array except the first line get deleted instead of the
single target element as chosen by $inputentry. Here is the exact code being
used:

open (ADDRESSES, "<data/addressbook.txt") or die "Can't open file: $!";
my (@entrys, %entrys) = <ADDRESSES>;
close(ADDRESSES);

$inputentry = $form{'recipient'};

chomp foreach @entrys;
@entrys{@entrys} = ();
delete $entrys{$inputentry} if exists $entrys{$inputentry};

open (ADDRESSES, ">data/addressbook.txt") or die "Can't open file: $!";
flock (ADDRESSES, LOCK_EX) or die "Can't lock file: $!";
print ADDRESSES @entrys;
close(ADDRESSES);

Also if I replace the value of $inputentry with a definative value that is
found in the text file such as:

$inputentry = "Smith|[email protected]";

The result is the same ... all lines in the array are removed except the
first. Didi i overlook something? TIA!

RTV
 
K

ko

Robert TV wrote:

[snip]
$inputentry = $form{'recipient'};

In your previous post, you had:

$inputentry = "$form{'name'}|$form{'email'}";

This will be the key entry for the hash you build next. Add that
statement back to build/use the hash.
chomp foreach @entrys;
@entrys{@entrys} = ();
delete $entrys{$inputentry} if exists $entrys{$inputentry};

The elements of @entrys are not affected. They only supply the keys to
the hash, except for the entry that you want to delete. So you have to
write the *hash* to your textfile, *not* the array:

print join("\n", keys %entrys);

I probably should have called the hash something other than '%entrys'
to make it clearer...

HTH - keith
 

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

Staff online

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,119
Latest member
IrmaNorcro
Top