diff --git a/lib/Subtitle/BASE.pm b/lib/Subtitle/BASE.pm index 4bda324..00924b5 100644 --- a/lib/Subtitle/BASE.pm +++ b/lib/Subtitle/BASE.pm @@ -19,56 +19,6 @@ sub log { return 1; } -sub parse_timing { - my ($self, $str) = @_; - my $time = 0.0; - return unless $str =~ m/(\d+):(\d+):(\d+)([.,])(\d+)/oi; - my ($hrs, $min, $sec, $delim, $msec) = ($1, $2, $3, $4, $5); - if ($msec < 0 or $msec > 999) { - $self->log(warn => "wrong mseconds part of timing: $msec"); - return; - } - if ($sec < 0 or $sec > 59) { - $self->log(warn => "wrong seconds part of timing: $sec"); - return; - } - if ($min < 0 or $min > 59) { - $self->log(warn => "wrong minutes part of timing: $sec"); - return; - } - if ($hrs < 0) { - $self->log(warn => "wrong minutes part of timing: $sec"); - return; - } - given (length("$msec")) { - when ("3") { $time += $msec * 0.001; } - when ("2") { $time += $msec * 0.01; } - when ("1") { $time += $msec * 0.1; } - default { - $self->log(error => "abnormal length of mseconds part"); - return; - } - } - $time += $sec; - $time += $min * 60; - $time += $hrs * 60 * 60; - return $time; -} - -sub build_timing { - my ($self, $time, $prec) = @_; - $prec //= 2; - my ($hrs, $min, $sec, $msec, $rest); - $hrs = int($time / 3600); - $rest = $time - ($hrs * 3600); - $min = int($rest / 60); - $rest = $rest - ($min * 60); - $sec = int($rest / 1); - $msec = sprintf "%.${prec}f", ($rest - ($sec * 1)); - $msec =~ s/^0\.//o; - return sprintf($self->{timing_fmt}, $hrs, $min, $sec, $msec); -} - sub events { my ($self) = @_; diff --git a/lib/Subtitle/Utils.pm b/lib/Subtitle/Utils.pm index 42063ca..266bab8 100644 --- a/lib/Subtitle/Utils.pm +++ b/lib/Subtitle/Utils.pm @@ -7,10 +7,12 @@ use base 'Exporter'; our @EXPORT_OK = qw( chomp_all strip_bom trim + make_timing parse_timing ); our %EXPORT_TAGS = ( string => [qw(chomp_all strip_bom trim)], + timing => [qw(make_timing parse_timing)], ); @@ -31,6 +33,48 @@ sub trim { $_ =~ s/(^\s+|\s+$)//go for @_; } +## timing functions + +sub make_timing { + my ($time) = @_; + my ($hrs, $min, $sec, $msec, $rest); + $hrs = int($time / 3600); + $rest = $time - ($hrs * 3600); + $min = int($rest / 60); + $rest = $rest - ($min * 60); + $sec = int($rest / 1); + $msec = sprintf "%.0f", (($rest - $sec) * 1000); + return ($hrs, $min, $sec, $msec); +} + +sub parse_timing { + my ($str) = @_; + my $time = 0.0; + return unless $str =~ m/(\d+):(\d+):(\d+)([.,])(\d+)/oi; + my ($hrs, $min, $sec, $delim, $msec) = ($1, $2, $3, $4, $5); + if ($msec < 0 or $msec > 999) { + return -1; # wrong mseconds part of timing + } + if ($sec < 0 or $sec > 59) { + return -1; # wrong seconds part of timing + } + if ($min < 0 or $min > 59) { + return -1; # wrong minutes part of timing + } + if ($hrs < 0) { + return -1; # wrong minutes part of timing + } + my $msec_len = length $msec; + if ($msec_len == 3) { $time += $msec * 0.001; } + elsif ($msec_len == 2) { $time += $msec * 0.01; } + elsif ($msec_len == 1) { $time += $msec * 0.1; } + else { return -1; } # abnormal length of mseconds part + $time += $sec; + $time += $min * 60; + $time += $hrs * 60 * 60; + return $time; +} + 1; =pod @@ -66,4 +110,21 @@ In-place strips Unicode's BOM (Byte Order Mark) from line. In-place strips leading and trailing spaces from the given string +=head1 FUNCTIONS / TIMING + +=head2 C + + my ($hrs, $min, $sec, $msec) = make_timing($time); + printf "%d:%02d:02d.%s", $hrs, $min, $sec, $msec; + +Takes float number of seconds and returns array with components of timing split by units. + +=head2 C + + my $time = parse_timing($string); + +Takes string like "HH:MM:SS.MSEC" and returns float number of seconds + +On parse error returns -1 + =cut diff --git a/t/utils-timing.t b/t/utils-timing.t new file mode 100644 index 0000000..80f61c8 --- /dev/null +++ b/t/utils-timing.t @@ -0,0 +1,44 @@ +use strict; +use warnings; + +use Test::More tests => 11; + +use Subtitle::Utils qw(:timing); + +my ($timing, $time); + +$timing = "123:11:15.459"; +$time = parse_timing($timing); +is($time, (123 * 3600 + 11 * 60 + 15 + 0.459)); + +$timing = "123:11:15.45"; +$time = parse_timing($timing); +is($time, (123 * 3600 + 11 * 60 + 15 + 0.450)); + +$timing = "123:11:15.4"; +$time = parse_timing($timing); +is($time, (123 * 3600 + 11 * 60 + 15 + 0.400)); + +$timing = "123:11:15,4"; +$time = parse_timing($timing); +is($time, (123 * 3600 + 11 * 60 + 15 + 0.400)); + +$timing = "123:60:15.45"; +$time = parse_timing($timing); +is($time, -1); + +$timing = "123:11:65.45"; +$time = parse_timing($timing); +is($time, -1); + +$timing = "123:11:15.4500"; +$time = parse_timing($timing); +is($time, -1); + +my ($hrs, $min, $sec, $msec); + +($hrs, $min, $sec, $msec) = make_timing(8 * 3600 + 11 * 60 + 15 + 0.46); +is($hrs, 8); +is($min, 11); +is($sec, 15); +is($msec, 460);