1

I'm working on a project and, due to a simple but very unfortunate mistake, need to rewrite a bunch of timestamps in a file; specifically, I need to take the final part of each timestamp and divide it by 30. For example, if the file contains:

"blahblahblah[00:05:25]randomblah[01:22:13]"

then i need it to say

"bahblahblah[00:05:833]randomblah[01:22:433]"

After realizing that pure regex can't handle the probem, as it only deals with character and not numbers, a little bit of googling pointed me toward a Perl one-liner, which I am trying to modify to fit my purposes. Here's what I have so far:

perl -pi.bak -e 's/\d\d:\d\d:($1/30)!/e

However, I have a syntax error "around /30". Can anybody help with this, as well as elucidate how it works? I get the line-by-line stuff, but not the expression part. Thanks!

030
  • 10,842
  • 12
  • 78
  • 123
spiffl
  • 23
  • 7
  • At a minimum you're going to run into the issue of the / being your delimiter character -- you're trying to do `s//e`, but you're giving perl `s//30/e`, which is too many arguments. Try escaping that second slash: `($1\/30)`. – zebediah49 Jul 22 '14 at 18:26
  • Do you want the numbers *rounded* or *truncated*? For instance, do you want to replace `[01:01:29]` with `[01:01:966]` or `[01:01:967]`? And what version of Perl are you running? – Borodin Jul 22 '14 at 19:40

2 Answers2

0

You can use alternate delimiters, such as s!!!. You need 2 capture groups: one for hours:minutes, and the other for the modified seconds. You need to use the g modifier to change all instances on a line. Refer to s/PATTERN/REPLACEMENT/ in perlop.

use warnings;
use strict;

$_ = 'blahblahblah[00:05:25]randomblah[01:22:13]';
s!(\d{2}:\d{2}:)(\d{2})!$1 . int(1000*$2/30)!ge;
print "$_\n";

__END__

blahblahblah[00:05:833]randomblah[01:22:433]
toolic
  • 57,801
  • 17
  • 75
  • 117
  • The OP has a `perl -pe'...'` command line that doesn't work. I think this is too far removed to be very useful. Also `\d\d` is more brief than `\d{2}`, but the explicit semantics of the latter makes it a close call – Borodin Jul 23 '14 at 02:28
0

Your proposed solution

perl -pi.bak -e 's/\d\d:\d\d:($1/30)!/e

doesn't work for a number of reasons; primarily that your substitution s/// doesn't have two proper parameters. On the face of it you want to replace something that matches \d\d:\d\d:($1 with 30)!.

I'm not clear what you mean by the exclamation mark !, but I think you intended something more like

perl -pi.bak -e 's{(\d\d:\d\d:)(\d\d)}{$1.$2/30}eg'

which saves and restores the first two fields and divides the third field by 30. Unfortunately that's not quite right as it gives you

97blahblahblah[00:05:0.833333333333333]randomblah[01:22:0.433333333333333]

with your sample data.

So instead you need the first three digits of the quotient after dividing by 30. If you want the closest integer and you have a fairly recent version of Perl, this one-line solution should work for you. It prints the modified text to STDOUT. If you want to modifiy the file in-place then you can add -i.bak as in your own version.

perl -pe's{\d\d:\d\d:\K(\d\d)}{sprintf "%.0f", $1/30*1000}ge' myfile
Borodin
  • 126,100
  • 9
  • 70
  • 144