views:

106

answers:

3

There's a file dummy.txt

The contents are:

 9/0/2010
 9/2/2010
 10/11/2010

I have to change the month portion (0,2,11) to +1, ie, (1,3,12) I wrote the substitution regex as follows

 $line =~ s/\/(\d+)\//\/\1+1\//;

It's is printing

9/0+1/2010
9/2+1/2010
10/11+1/2010

How to make it add - 3 numerically than perform string concat? 2+1??

+10  A: 

Three changes:

  • You'll have to use the e modifier to allow an expression in the replacement part.
  • To make the replacement globally you should use the g modifier. This is not needed if you've one date per line.
  • You use $1 on the replacement side, not a backreference

This should work:

$line =~ s{/(\d+)/}{'/'.($1+1).'/'}eg;

Also if your regex contains the delimiter you're using(/ in your case), it's better to choose a different delimiter ({} above), this way you don't have to escape the delimiter in the regex making your regex clean.

codaddict
awesome!, it worked - if you don't mind can you explain the s{} syntax - I mean is it possible to achieve it with s/ rather than s{
@OP: I've updated my answer. `s///` is equivalent to `s{}{}`, just that it uses a different delimiter and will save you from escaping those `/`.
codaddict
While not required, using the 'x' modifier to your regular expressions greatly enhances their readability: s{ / (\d+) / }{ '/' . ($1+1) . '/'}egx
Prakash K
+1  A: 

How about this?

$ cat date.txt 
9/0/2010
9/2/2010
10/11/2010
$ perl chdate.pl 
9/1/2010
9/3/2010
10/12/2010
$ cat chdate.pl 
use strict;
use warnings;

open my $fp, '<', "date.txt" or die $!;

while (<$fp>) {
    chomp;
    my @arr = split (/\//, $_);
    my $temp = $arr[1]+1;
    print "$arr[0]/$temp/$arr[2]\n";
}

close $fp;
$ 
Lazer
thanks for this approach - I will keep exploring perl - I have accepted another answer as it solves with a single line
Yes, those answers are definitely better, I did not know about expressions either.
Lazer
A: 

this works: (e is to evaluate the replacement string: see the perlrequick documentation).

$line = '8/10/2010';
$line =~ s!/(\d+)/!('/'.($1+1).'/')!e;

print $line;

It helps to use ! or some other character as the delimiter if your regular expression has / itself.


You can also use, from this question in http://stackoverflow.com/questions/3939919/can-perl-string-interpolation-perform-any-expression-evaluation

$line = '8/10/2010';
$line =~ s!/(\d+)/!("/@{[$1+1]}/")!e;

print $line;

but if this is a homework question, be ready to explain when the teacher asks you how you reach this solution.

動靜能量
Thanks for mentioning about the delimiter character!
oh no no!, not a homework question, I'll explain it to you - my solution worked but am wondering if there's a better approach.I'm creating a database of tracking all the users who have used an application. The authentication system is external - however it writes a separate file for each login.I am trying to get the login-time by capturing the file-creation time and insert in SQL Server DATETIME format.My first perl program that I wrote missed this important fact - so most of the dates were in 0/0/2010 format(Incompatible with DATETIME). running Perl program again with changes was costly