pglinx has asked for the wisdom of the Perl Monks concerning the following question:

I am comparing 2 dates and then I need to empty a field if I have it matching and all that, I just cant seem to remove the text I want to remove.
#!/usr/local/bin/perl5 # create a date+time string $shortdate = `date +"%D"`; chop ($shortdate); print "$shortdate\n"; $inhouse = "Open House Information"; open(FILE, "dbase1.exm") || die "I can't open that because: $!\n"; while(<FILE>) { chop; @all = split(/\n/); foreach $line (@all) { local($AA, $BB, $CC, $DD, $EE, $FF, $GG, $HH, $II, $JJ, $KK, $LL, +$MM, $NN, $OO, $PP, $QQ, $RR, $SS, $TT, $UU, $VV, $WW, $XX) = split(/ +","/, $line); $date = $shortdate; $date_from_db = $XX; $date1 = "$date"; @newdate = split(/\//,$date1); $formate_date1 = "$newdate[2]" . "$newdate[1]" . "$newdate[0]"; $date2 = "$date_from_db"; @newdate = split(/\//,$date2); $formate_date2 = "$newdate[2]" . "$newdate[1]" . "$newdate[0]"; if ($formate_date1 > $formate_date2) { $kill = "yes"; } else { $kill = "no"; } if ($inhouse eq "$WW" && $kill eq "yes") { print "$line\n"; print "$XX\n"; print "$formate_date1\n"; print "$formate_date2\n"; print "$kill\n"; print "$WW\n"; # this is the problem need the text removed from $WW field $WW =~ s/Open House Information//g; } } } close(FILE, "dbase1.exm")

20070801 Janitored by Corion: Changed PRE tags to code tags, as per Writeup Formatting Tips

Replies are listed 'Best First'.
Re: replace in lines
by ikegami (Patriarch) on Aug 01, 2007 at 19:11 UTC

    Your code already does exactly that.

    $WW = 'foo Open House Information bar'; print("$WW\n"); $WW =~ s/Open House Information//g; print("$WW\n");
    foo Open House Information bar foo bar

      Indeed. I concur that there is nothing wrong with your sed text replacement. Your code is printing the value of $WW before it is modified, but not after.

      Additional comments:

      Use 'my' instead of 'local' in your array assignment. It is the correct localization for what you are doing.

      Text::CSV_XS does comma separated value parsing much better than you can. Since your values have text in them, they could also have embedded sequences that will throw off your simple parser.

      You don't have to "QUOTE" singleton right value scalars.

      My preference is to make flag values integers so that you can say something like this:

      my $kill_flag++ if ($formate_date1 > $formate_date2); if ($kill_flag) { }
      Of course, your $kill value is purely arbitrary unless you intend to use it later as well. Why not just put the actual test in the logic encapsulating the print block.

      My preference is to mark all variables using 'my' variable scoping upon their first use. It localizes the value and it can protect you in case you make this a required external code block or move it to a CLASS.

      It prints it, but it does not replace it in the line in the file.... Any other sujestions?

        True. Changing a variable in memory will not change a file. Except when using Tie::File which should be perfect for you.

        Normally, to change something in a file, you need to read the file, do your change, and write the file back out.

        use strict; use warnings; use POSIX qw( strftime ); use Text::CSV qw( ); use Tie::File qw( ); use constant INHOUSE =>"Open House Information"; { my $today = strftime('%Y/%m/%d', localtime()); tie(my @db, 'Tie::File', 'dbase1.exm') or die("Unable to open database: $!\n"); my $csv = Text::CSV->new(); foreach my $line (@db) { $csv->parse($line) or die("Unable to parse \"$line\"\n"); my @fields = $csv->fields(); my ($status, $date) = $fields[22, 23]; # Convert date to sortable format. my ($m, $d, $y) = split(/\//, $date); $date = "20$y/$m/$d"; my $kill = ($date < $today); # Are you sure this isn't backward +s? if ($status eq INHOUSE && $kill) { $status = ''; } # Reassemble the line and updated the file. $fields[22] = $status; $csv->combine(@fields) or die("Unable to recreate line from fields @fields\n"); # Changing $line causes the file to be updated. $line = $csv->string(); } untie @db; }

        If you're trying to remove the entire line, it's even easier:

        use strict; use warnings; use POSIX qw( strftime ); use Text::CSV qw( ); use Tie::File qw( ); use constant INHOUSE =>"Open House Information"; { my $today = strftime('%Y/%m/%d', localtime()); tie(my @db, 'Tie::File', 'dbase1.exm') or die("Unable to open database: $!\n"); my $csv = Text::CSV->new(); @db = grep { $csv->parse($line) or die("Unable to parse \"$line\"\n"); my @fields = $csv->fields(); my ($status, $date) = $fields[22, 23]; # Convert date to sortable format. my ($m, $d, $y) = split(/\//, $date); $date = "20$y/$m/$d"; $status ne INHOUSE || $date >= $today } @db; untie @db; }

        I find it interesting that you think this code sample actually writes data back to the file. Is there a part of the code you are not including?

        If that is the case, you may not realize that localizing $WW means that you lose the value of that variable when you leave the current scope (go beyond the encapsulating closing curly bracket).

        If you really intend to save the data back to the original file, you have a lot more work ahead of you. This code will have a number of pitfalls, including dropping the changed value before you write it, or writing to a file you are reading from before finishing the initial processing of the original contents.

        Messy!