Thread: Editing files

Page 1 of 2 12 Last
  • Jump to page:
    #1
  1. No Profile Picture
    Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2001
    Posts
    9
    Rep 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);
  2. #2
  3. No Profile Picture
    PerlGuy
    Devshed Novice (500 - 999 posts)

    Join Date
    Jan 2001
    Posts
    720
    Rep Power
    46

    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
  4. #3
  5. No Profile Picture
    PerlGuy
    Devshed Novice (500 - 999 posts)

    Join Date
    Jan 2001
    Posts
    720
    Rep Power
    46

    Wink


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

    If that doesn't work then let me know.
    - dsb -
    Perl Guy
  6. #4
  7. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2001
    Location
    Lithuania
    Posts
    7
    Rep 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]
  8. #5
  9. No Profile Picture
    Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Aug 2000
    Location
    Indiana
    Posts
    614
    Rep Power
    19
    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.
  10. #6
  11. No Profile Picture
    Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2001
    Posts
    9
    Rep 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.

  12. #7
  13. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2001
    Location
    Lithuania
    Posts
    7
    Rep Power
    0
    anything wrong with
    http://forums.devshed.com//showthrea...1746#post37589 ?

    [Edited by Sonis on 03-08-2001 at 05:16 AM]
  14. #8
  15. No Profile Picture
    Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Aug 2000
    Location
    Indiana
    Posts
    614
    Rep Power
    19
    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.
  16. #9
  17. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2001
    Location
    Lithuania
    Posts
    7
    Rep 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...
  18. #10
  19. No Profile Picture
    Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Aug 2000
    Location
    Indiana
    Posts
    614
    Rep Power
    19
    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]
  20. #11
  21. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2001
    Location
    Lithuania
    Posts
    7
    Rep 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=cache...n/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]
  22. #12
  23. No Profile Picture
    Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2001
    Posts
    9
    Rep 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!
  24. #13
  25. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2001
    Location
    Lithuania
    Posts
    7
    Rep 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]
  26. #14
  27. No Profile Picture
    Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Aug 2000
    Location
    Indiana
    Posts
    614
    Rep Power
    19
    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.
  28. #15
  29. No Profile Picture
    Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2001
    Posts
    9
    Rep 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!
Page 1 of 2 12 Last
  • Jump to page:

IMN logo majestic logo threadwatch logo seochat tools logo