Perl Programming
 
Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
User Name:
Password:
Remember me
Go Back   Dev Shed ForumsProgramming LanguagesPerl Programming

Reply
Add This Thread To:
  Del.icio.us   Digg   Google   Spurl   Blink   Furl   Simpy   Y! MyWeb 
Thread Tools Search this Thread Rate Thread Display Modes
 
Unread Dev Shed Forums Sponsor:
  #1  
Old March 7th, 2001, 12:20 PM
Paul_Statham Paul_Statham is offline
Member
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Mar 2001
Posts: 9 Paul_Statham User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: < 1 sec
Reputation Power: 0
Wink

Ok I posted earlier on how to edit flat files via http. I've figured that out now but I still have probs. This is just a trial before I add it to the main script. So I created a file called called "test.txt" with the following.

sno|name
-----------
1|shiju
2|thomas
3|rajesh
4|james

Say I want to change # 3 to PETER THOMAS, all I do is I load all the contents of "test.txt" into a file called "temp.txt" unless the sno is 3. Once this is done I Load the contents of temp.txt into an array, I then basically delete all the contents of test.txt and re-print the contents of the array into the file. Once this is done I close the files ,re-open test and append the ammended record onto the end. Yes this does work, woopee I thought to myself, one prob it prints the results out to the file like so.

1|shiju
2|thomas
4|james

3|PETER THOMAS

How do I get it so that it looks like

1|shiju
2|thomas
4|james
3|PETER THOMAS

Here's the code incase u were wondering.

Code:
#!/usr/bin/perl


open(TEMP,">temp.txt") || die "Error creating a file $!\n";

#open a temperary file for storing the data from test.txt

open(DB,"test.txt") || die "Error opening database $!\n";
#@test = <DB>;
#open test.txt file

while(<DB> ){
chomp;
($sno,$name)=split(/|/,$_);

if ($sno != "3") {print TEMP "$_\n";}
  
#print the records to the temp.txt except sno 3
}

#rename the temp.txt to test.txt

#now 3rd row has been deleted from the database. 

close(DB);
close(TEMP);

open (TEMP,"temp.txt") || die "Error reading file $!\n";
@temp = <TEMP>;

open (DB,">test.txt") || die "Error reading file $!\n";
seek(DB,0,0);
print DB "@temp";
close(DB);

#now just appned the 3rd row to the test.txt


open(DB,">>test.txt") || die "Error open database $!n";
seek(DB,0,2);

#open database in append mode..

print DB "3|PETER THOMAS\n";

close(DB);


Reply With Quote
  #2  
Old March 7th, 2001, 12:48 PM
dsb dsb is offline
PerlGuy
Dev Shed Novice (500 - 999 posts)
 
Join Date: Jan 2001
Posts: 714 dsb User rank is Sergeant Major (2000 - 5000 Reputation Level)dsb User rank is Sergeant Major (2000 - 5000 Reputation Level)dsb User rank is Sergeant Major (2000 - 5000 Reputation Level)dsb User rank is Sergeant Major (2000 - 5000 Reputation Level)dsb User rank is Sergeant Major (2000 - 5000 Reputation Level)dsb User rank is Sergeant Major (2000 - 5000 Reputation Level) 
Time spent in forums: 2 Days 15 h 44 m 20 sec
Reputation Power: 36
Send a message via AIM to dsb
Talking

This is just a hunch, but I think the problem starts in the original 'test.txt' that looks like this:
Code:
sno|name 
----------- 
1|shiju 
2|thomas 
3|rajesh 
4|james 


I would check to see if there is an extra empty line after '4|james'. If there is take it out and you should be fine. The problem is that even if the line is empty the newline character counts as a 'defined' line. So when you say:
Code:
while ( <DB> ) {
    #code
}

the empty line gets picked up. You chomp it but then you print to the temp file '$_\n' which just puts it in again. The same thing happens then when you close and reopen the files.

Try that.

Hope that helps.
__________________
- dsb -
Perl Guy

Reply With Quote
  #3  
Old March 7th, 2001, 04:05 PM
dsb dsb is offline
PerlGuy
Dev Shed Novice (500 - 999 posts)
 
Join Date: Jan 2001
Posts: 714 dsb User rank is Sergeant Major (2000 - 5000 Reputation Level)dsb User rank is Sergeant Major (2000 - 5000 Reputation Level)dsb User rank is Sergeant Major (2000 - 5000 Reputation Level)dsb User rank is Sergeant Major (2000 - 5000 Reputation Level)dsb User rank is Sergeant Major (2000 - 5000 Reputation Level)dsb User rank is Sergeant Major (2000 - 5000 Reputation Level) 
Time spent in forums: 2 Days 15 h 44 m 20 sec
Reputation Power: 36
Send a message via AIM to dsb
Wink

Did you try to do what I told you to do?

If that doesn't work then let me know.

Reply With Quote
  #4  
Old March 7th, 2001, 04:09 PM
Sonis Sonis is offline
Junior Member
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Mar 2001
Location: Lithuania
Posts: 7 Sonis User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: < 1 sec
Reputation Power: 0
here you are

test.txt before:
----------------
any lines here
1|linas
2|marius
3|jonas
4|darius
any lines here

----------------
here is the code you need
Code:
#!/usr/bin/perl

$filename = "test.txt";
$texttoreplace = "3|PETER THOMAS";

#find out whitch line to change
$texttoreplace =~ m/^([0-9]*)/; #get first digits into $1
$whitchline = $1;

#load data
open (FILE, "$filename"); @lines = <FILE>; close (FILE);

#replace
foreach (@lines){
(m/^([0-9]*)/) && ($1 eq $whitchline) && ($_ = "$texttoreplace\n");
}

#save data
open (FILE, ">$filename"); print FILE @lines; close(FILE);


test.txt after:
----------------
any lines here
1|linas
2|marius
3|PETER THOMAS
4|darius
any lines here

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

[Edited by Sonis on 03-08-2001 at 12:03 PM]

Reply With Quote
  #5  
Old March 8th, 2001, 01:24 AM
JonLed JonLed is offline
Contributing User
Dev Shed Novice (500 - 999 posts)
 
Join Date: Aug 2000
Location: Indiana
Posts: 614 JonLed User rank is Corporal (100 - 500 Reputation Level)JonLed User rank is Corporal (100 - 500 Reputation Level)JonLed User rank is Corporal (100 - 500 Reputation Level)JonLed User rank is Corporal (100 - 500 Reputation Level) 
Time spent in forums: 4 h 49 m 49 sec
Reputation Power: 10
Without reading anybody's replies, I can tell you 2 things that are wrong with your code:
Code:
($sno,$name)=split(/|/,$_);

You need to slash out the pipe (|) because that is a character used in a regex (which is what the split command uses).
Code:
if ($sno != "3") {print TEMP "$_\n";}

You can't use == or != when comparing a string value. You need to be using 'eq':
Code:
if ($sno eq "3") {print TEMP "$_\n";}


I highly suggest you use the method that you set out to use in the first place and not the regex idea given to you by the others (thought they're code if functional and might work, there could be a million times the code doesn't work).

If you really want to use a regex to get the 'key' of the line (number), then use one like this:
Code:
$var =~ m/^(\d+)\|/;
$found = $1;

that will look for one or more digits (incase you get above 9, which was the major flaw with the other's code) and will look until it reaches the pipe.

Reply With Quote
  #6  
Old March 8th, 2001, 05:12 AM
Paul_Statham Paul_Statham is offline
Member
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Mar 2001
Posts: 9 Paul_Statham User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: < 1 sec
Reputation Power: 0
Arrow

So dsb, r u saying that every time I use \n I have chomp it? Or if I open a file to chomp, also one thing that it didn't show when I posted was that number 2 and 4 were also indented by a space or two.


Reply With Quote
  #7  
Old March 8th, 2001, 06:10 AM
Sonis Sonis is offline
Junior Member
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Mar 2001
Location: Lithuania
Posts: 7 Sonis User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: < 1 sec
Reputation Power: 0
anything wrong with
http://forums.devshed.com//showthre...11746#post37589 ?

[Edited by Sonis on 03-08-2001 at 05:16 AM]

Reply With Quote
  #8  
Old March 8th, 2001, 11:00 AM
JonLed JonLed is offline
Contributing User
Dev Shed Novice (500 - 999 posts)
 
Join Date: Aug 2000
Location: Indiana
Posts: 614 JonLed User rank is Corporal (100 - 500 Reputation Level)JonLed User rank is Corporal (100 - 500 Reputation Level)JonLed User rank is Corporal (100 - 500 Reputation Level)JonLed User rank is Corporal (100 - 500 Reputation Level) 
Time spent in forums: 4 h 49 m 49 sec
Reputation Power: 10
Well what happens if a number starts with zero? 1-9 wont catch it. And:
foreach (@lines){
Code:
(m/^([1-9]*)/) && ($1 eq $whitchline) && ($_ = "$texttoreplace\n");
}

I don't even know if this would work... you're just doing a bunch of test operators. I'm thinking that it might work because perl, by nature, will check the first two tests, and if they fail wont check the third. If the 1st 2 do pass, then it'll 'test' the third one, which will set $_ equal to that and return true -- but that's just a sloopy way of doing it IMHO.

Reply With Quote
  #9  
Old March 8th, 2001, 01:01 PM
Sonis Sonis is offline
Junior Member
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Mar 2001
Location: Lithuania
Posts: 7 Sonis User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: < 1 sec
Reputation Power: 0
yeah there should be [0-9].
with (m/^([0-9]*)/) && ($1 eq $whitchline) && ($_ = "$texttoreplace\n");
everything is fine, I need to execute 3rd condition only when first two are true.
it works fine and is at least twice shorter than yours

nevermind

______________
just expected thanks for that code...

Reply With Quote
  #10  
Old March 8th, 2001, 01:20 PM
JonLed JonLed is offline
Contributing User
Dev Shed Novice (500 - 999 posts)
 
Join Date: Aug 2000
Location: Indiana
Posts: 614 JonLed User rank is Corporal (100 - 500 Reputation Level)JonLed User rank is Corporal (100 - 500 Reputation Level)JonLed User rank is Corporal (100 - 500 Reputation Level)JonLed User rank is Corporal (100 - 500 Reputation Level) 
Time spent in forums: 4 h 49 m 49 sec
Reputation Power: 10
Well I didn't even offer a solution, so it's literally impossible for yours to be short.

The only reason that your works is because of what I'd consider a bug in perl. Any other language would check all three, regardless of what the other two result in.

Here's a much better method, IMO (Note: this is based off your existing 'method', I would probably approach it an entirely different way):
Code:
foreach (@lines) {
    chomp;
    $_ = (/^$whitchline\|/) ? $texttoreplace . $/ : $_ . $/;
}

This will work every time and doesn't rely on a perl bug to work.

[Edited by JonLed on 03-08-2001 at 12:29 PM]

Reply With Quote
  #11  
Old March 8th, 2001, 05:58 PM
Sonis Sonis is offline
Junior Member
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Mar 2001
Location: Lithuania
Posts: 7 Sonis User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: < 1 sec
Reputation Power: 0
Talking bug?

JonLed,
before considering it's a bug or not, check this out in Oreilly's book "Learning Perl" Chapter 9.6 or http://www.google.com/search?q=cach...rn/ch09_06.php3

So.. my solution is not only shorter but it's also faster.
Because it executes only first operator, and executes all three of them only when we need to change that line. But yours executes two(not counting chomp) for every line.

(sure it would be faster if there is only one line in the file)

Sonis



[Edited by Sonis on 03-08-2001 at 05:30 PM]

Reply With Quote
  #12  
Old March 9th, 2001, 01:17 PM
Paul_Statham Paul_Statham is offline
Member
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Mar 2001
Posts: 9 Paul_Statham User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: < 1 sec
Reputation Power: 0
Hang on

Explain these regexps to me would you, I'm still pretty new to all this. The methods which you guys are going on about would they still work from form input? I say this because to edit the record, the final version won't have a static bit to append rather it will be defined via the browser!

Reply With Quote
  #13  
Old March 9th, 2001, 03:30 PM
Sonis Sonis is offline
Junior Member
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Mar 2001
Location: Lithuania
Posts: 7 Sonis User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: < 1 sec
Reputation Power: 0
Code:
(m/^([0-9]*)/) && ($1 eq $whitchline) && ($_ = "$texttoreplace\n"); 

It means: find the number at the beginning(^) of the line, if you found it, check if it's equal $whitchline(we got it from $texttoreplace), if this is also True, then replace this line with $linetoreplace..

Sure it will work fine with value from form. Just add some code before.
smth like..

use CGI;

$mycgi = CGI::new;
$texttoreplace = $mycgi->param('inputname');

Sonis
____________
just simple...

[Edited by Sonis on 03-09-2001 at 02:32 PM]

Reply With Quote
  #14  
Old March 11th, 2001, 02:34 AM
JonLed JonLed is offline
Contributing User
Dev Shed Novice (500 - 999 posts)
 
Join Date: Aug 2000
Location: Indiana
Posts: 614 JonLed User rank is Corporal (100 - 500 Reputation Level)JonLed User rank is Corporal (100 - 500 Reputation Level)JonLed User rank is Corporal (100 - 500 Reputation Level)JonLed User rank is Corporal (100 - 500 Reputation Level) 
Time spent in forums: 4 h 49 m 49 sec
Reputation Power: 10
1) You're not going to find that 'feature' (bug IMO) in any other language, so you're getting stuck on a really bad programming habit.

2) Mine would actually execute faster because it doesn't evaluate any double quotes. Yours also has too many parts (if you wanted to do it in your 'style'). You don't need the 2nd evaluation if you make the first one smarter.

3) Mine only evaluates one time (not counting chomp). Just because you don't understand the ?: syntax doesn't mean you can go around assuming things about it. As as for the chomp, is just to ensure that the lines are uniform.

I understand the nature of perl, but just because perl happens to support something (as sloppy as that) doesn't mean you should get in the habit of using it. What if the person needed to do more than just change the value of a variable? Then you've gone and left this person out in the cold.

Reply With Quote
  #15  
Old March 11th, 2001, 09:31 AM
Paul_Statham Paul_Statham is offline
Member
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Mar 2001
Posts: 9 Paul_Statham User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: < 1 sec
Reputation Power: 0
So If I want more than nine records I should use

Code:
$var =~ m/^(\d+)\|/;
$found = $1;


And not

Code:
$texttoreplace =~ m/^([0-9]*)/;


And with that $found = $1; whats that do? Is that some sort of flag to break out of a loop? Is this the line you guys are arguing over, I have to say I understand the second example more than the first whats (\d+) do in a regexp? Some more explanation needed please!

Reply With Quote
Reply