Replace an occurrence of a regexp with a function call on a substringof the match, multiple times on


D

David Karr

I have a pattern in an input file that looks like this:

latestTime="1379353492000"

I need to replace this with something like this:

latestTime="2013-09-16 10:34:33"

This pattern will occur in multiple lines in a file, and multiple times on a single line.

The hardest part of this seems to be to pass the milliseconds value into "strftime" as the replacement portion of the substitution regexp, for each occurrence. I can't get this to work.

This is what I have so far, and I hope I don't have to use that very strange syntax to call a function in the string (I found some references with examples like this):

#! /bin/perl
use English;
use strict;
use POSIX qw( strftime );

$| = 1;

while (my $line = <STDIN>) {
if ($line =~ /(^.*latestTime=")([0-9]+)(".*$)/) {
"\n";
$line =~ s/latestTime="([0-9]+)"/latestTime="${\strftime("%Y-%m-%d %H:%M:%S", localtime($1/1000))}"/g';
}
print $line;
}
 
Ad

Advertisements

B

Ben Bacarisse

David Karr said:
I have a pattern in an input file that looks like this:

latestTime="1379353492000"

I need to replace this with something like this:

latestTime="2013-09-16 10:34:33"

This pattern will occur in multiple lines in a file, and multiple
times on a single line.

The hardest part of this seems to be to pass the milliseconds value
into "strftime" as the replacement portion of the substitution regexp,
for each occurrence. I can't get this to work.

This is what I have so far, and I hope I don't have to use that very
strange syntax to call a function in the string (I found some
references with examples like this):

#! /bin/perl
use English;
use strict;
use POSIX qw( strftime );

$| = 1;

You probably don't need this (if you do, nothing in your problem
description suggest that you do). Also, since you "use English" it's
odd to then use the cryptic name for this variable. It's
$OUTPUT_AUTOFLUSH with "use English".
while (my $line = <STDIN>) {
if ($line =~ /(^.*latestTime=")([0-9]+)(".*$)/) {

You don't have to match the lines first -- just try the substitution you
want to do. Also, Perl has \d with is often better than writing [0-9].
"\n";
$line =~ s/latestTime="([0-9]+)"/latestTime="${\strftime("%Y-%m-%d %H:%M:%S", localtime($1/1000))}"/g';

You can use the "e" modifier to permit an expression in a substitution,
and you can put the whole text into strftime's format to get a simpler
expression:

$line =~ s!latestTime="(\d+)"!
strftime("latestTime=\"%Y-%m-%d %H:%M\"",
localtime($1/1000))!eg;

Because it's an expression, you can be free with the layout.
}
print $line;
}

Finally, this pattern of looping and printing is so common that Perl
provides a command-line options for it. You can therefore write this
sort of thing as a single command, should that be more convenient than a
script:

perl -MPOSIX -pe 's/\d+/strftime("%F", localtime($1))/eg'

(using a simplified example).
 
D

David Karr

You probably don't need this (if you do, nothing in your problem

description suggest that you do). Also, since you "use English" it's

odd to then use the cryptic name for this variable. It's

$OUTPUT_AUTOFLUSH with "use English".

Write Perl without cryptic syntax? What? :)

Thanks for the more expressive way to do this, and reminding me that I don't need it for this script.
while (my $line = <STDIN>) {
if ($line =~ /(^.*latestTime=")([0-9]+)(".*$)/) {



You don't have to match the lines first -- just try the substitution you

want to do. Also, Perl has \d with is often better than writing [0-9].


$line =~ s/latestTime="([0-9]+)"/latestTime="${\strftime("%Y-%m-%d %H:%M:%S", localtime($1/1000))}"/g';



You can use the "e" modifier to permit an expression in a substitution,

and you can put the whole text into strftime's format to get a simpler

expression:



$line =~ s!latestTime="(\d+)"!

strftime("latestTime=\"%Y-%m-%d %H:%M\"",

localtime($1/1000))!eg;



Because it's an expression, you can be free with the layout.

Outstanding. The "e" directive is definitely new to me. I'll have to read about that.
Finally, this pattern of looping and printing is so common that Perl

provides a command-line options for it. You can therefore write this

sort of thing as a single command, should that be more convenient than a

script:



perl -MPOSIX -pe 's/\d+/strftime("%F", localtime($1))/eg'

I'm writing this as a command-line filter tool, to be used with other filters, so I want the details in the script, not on the command line, but thanks for that option ayway.
 
D

David Karr

You can use the "e" modifier to permit an expression in a substitution,

and you can put the whole text into strftime's format to get a simpler

expression:

$line =~ s!latestTime="(\d+)"!
strftime("latestTime=\"%Y-%m-%d %H:%M\"",
localtime($1/1000))!eg;

Because it's an expression, you can be free with the layout.

I find this "e" directive curious. I can't find this documented anywhere. Is there a good reference for that?
 
Ad

Advertisements

B

Ben Bacarisse

I find this "e" directive curious. I can't find this documented
anywhere. Is there a good reference for that?

It's documented in "perlop" as part of the documentation of s///.
Technically it's called a modifier or an option (the latter was a
surprise to me but it's one of the terms used in the documentation).
 

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

Top