package Subtitle::Utils; use strict; use warnings; use base 'Exporter'; our @EXPORT_OK = qw( chomp_all strip_bom trim make_timing parse_timing round ); our %EXPORT_TAGS = ( string => [qw(chomp_all strip_bom trim)], timing => [qw(make_timing parse_timing)], ); ## string functions sub chomp_all { return unless $_[0]; $_[0] =~ s/[\r\n]+$//o; } sub strip_bom { return unless @_; return $_[0] =~ s/^\xEF\xBB\xBF//o; } sub trim { return unless $_[0]; $_[0] =~ s/(^\s+|\s+$)//go; } ## 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; } ## misc sub round { my ($value, $n) = @_; return sprintf "%.${n}f", $value; } 1; =pod =head1 NAME Subtitle::Utils -- usefull generic routines =head1 SYNOPSYS use Subtitle::Utils qw(:all); =head1 FUNCTIONS / STRINGS use Subtitle::Utils qw(:string); =head2 C chomp($line); In-place strips newlines (CR/LF) from line. Differs from standart chomp() than strips '\r', '\n' and it's combinaion, disregarding $/ =head2 C strip_bom($line); In-place strips Unicode's BOM (Byte Order Mark) from line. =head2 C trim($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 =head1 FUNCTIONS / MISC =head2 C say round(3.6, 0); # 4 say round(3.6, 1); # 4.1 Self-descriptive =cut