#!/usr/bin/env perl use 5.010; use strict; use warnings; sub split_string ($$;$) { my ($string, $offset, $length) = @_; die 'Input string is undefined!' unless defined $string; die 'Input string is a reference!' if ref $string; my $str_len = length $string; die 'Input string has zero length!' unless $str_len; die 'Offset is undefined!' unless defined $offset; die 'Offset is a reference!' if ref $offset; die 'Offset not an integer!' unless ''.$offset =~ /^[+-]?\d+$/; $offset = $str_len + $offset if $offset < 0; die 'Offset out of bounds!' if $offset >= $str_len; $length //= $str_len - $offset; die 'Length is a reference!' if ref $length; die 'Length not an integer!' unless $length =~ /^[+-]?\d+$/; if ($length < 0) { die 'Negative length out of bounds!' if abs $length >= $str_len; $string = substr $string, 0, $length; $str_len = length $string; die 'Offset out of bounds for negative length!' if $offset >= $str_len; $length = $str_len - $offset; } else { die 'Length out of bounds!' if $offset + $length > $str_len; } $string =~ /^(.{$offset})(.{$length})(.*)$/; return (($1 // ''), ($2 // ''), ($3 // '')); } my @test_data = ( [ qw{ATATTTATATTAT 0 3} ], [ qw{1234567890 0 4} ], [ qw{1234567890 3 4} ], [ qw{1234567890 6 4} ], [ qw{1234567890 9 1} ], [ undef, 0, 1 ], [ {}, 0, 1 ], [ '', 0, 1 ], [ '1234567890', undef, 1 ], [ '1234567890', [], 1 ], [ '1234567890', 'not a number', 1 ], [ '1234567890', 1.1, 1 ], [ '1234567890', 10, 1 ], [ '1234567890', 1 ], [ '1234567890', 1, sub {1} ], [ '1234567890', 1, 'not a number' ], [ '1234567890', 1, 1.1 ], [ '1234567890', -3, 2 ], [ '1234567890', 0, 10 ], [ '1234567890', 1, 10 ], [ qw{1234567890 0 -10} ], [ qw{1234567890 3 -6} ], [ qw{1234567890 3 -7} ], [ qw{1234567890 5 0} ], ); for (@test_data) { my ($string, $offset, $length) = @$_; my $i_string = $string // ''; my $i_offset = $offset // ''; my $i_length = $length // ''; say "string[$i_string] offset[$i_offset] length[$i_length]"; my ($left, $extract, $right) = eval { split_string $string, $offset, $length; }; if ($@) { warn '! ', $@; say '-' x 72; next; } say "left[$left] extract[$extract] right[$right]", " joined[@{[$left . $right]}]"; say '-' x 72; }