Perl Scripts ·
Perl Strings and Regex: substr, Replace and Rounding
By Manu Mathew · Last updated 4 October 2026
Text handling is where Perl earned its reputation, and a few tools cover most daily needs: substr, the substitution operator and sprintf. This page brings together several short notes I wrote between 2013 and 2014. I have rewritten them in one place, with tested examples and current advice, so you don’t have to piece the answer together from fragments.
Quick answer
substr($s, $offset, $length) takes part of a string, and negative offsets count from the end. s/old/new/ replaces the first match; add /g for every match and /r to return a new string. Wrap literal text in \Q…\E. Reorder parts with capture groups, and format decimals with sprintf '%.2f'.
I tested each example with Perl 5.40, using use strict and use warnings.
How do I take part of a string with substr?
Give substr the string, a starting offset and, optionally, a length; a fourth argument replaces that part in place.
use strict;
use warnings;
my $word = 'okay';
print substr($word, 2), "\n"; # ay (from offset 2 to the end)
print substr($word, 1, 2), "\n"; # ka (2 characters from offset 1)
print substr($word, -1), "\n"; # y (negative offsets count from the end)
my $text = 'Hello world';
substr($text, 0, 5, 'Hi'); # 4-argument form replaces in place
print "$text\n"; # Hi world
How do I replace text in a string?
Use the substitution operator s///: it changes the first match, or every match with /g.
use strict;
use warnings;
my $text = 'cat and cat food';
(my $one = $text) =~ s/cat/dog/; # first match only
print "$one\n"; # dog and cat food
my $all = $text =~ s/cat/dog/gr; # /g every match, /r returns a new string
print "$all\n"; # dog and dog food
# Replace literal text that may contain regex characters
my ($from, $to) = ('1+1', 'two');
(my $sum = 'Is 1+1 easy?') =~ s/\Q$from\E/$to/g;
print "$sum\n"; # Is two easy?
The older note wrapped this in a replace() subroutine. That is fine, but it passed the search text straight into the pattern, so characters such as +, . or ( changed its meaning. \Q…\E makes the text literal. The /r flag (Perl 5.14 and later) returns the changed copy and leaves the original alone.
How do I reorder parts of a string, such as a date?
Capture each part with parentheses, then put the captures back in the order you want.
use strict;
use warnings;
my $date = '2009-02-27'; # YYYY-MM-DD
(my $uk = $date) =~ s{(\d{4})-(\d{2})-(\d{2})}{$3/$2/$1};
print "$uk\n"; # 27/02/2009
# Named captures make the intent clearer
if ($date =~ /(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})/) {
print "$+{m}/$+{d}/$+{y}\n"; # 02/27/2009
}
Using s{…}{…} instead of slashes means the / characters in the replacement don’t need escaping. Named captures ((?<y>…), read back through %+) make longer patterns easier to follow. For real date handling, parse the date with Time::Piece and format it again.
How do I show a number with a fixed number of decimals?
sprintf '%.2f' rounds to two decimal places and returns a string; printf prints it directly.
use strict;
use warnings;
printf "%.2f\n", '10.0500000'; # 10.05
my $rounded = sprintf '%.2f', 3.14159;
print "$rounded\n"; # 3.14
# Binary floating point can surprise you on exact halves
printf "%.2f\n", 1.005; # 1.00, because 1.005 is stored as 1.00499999...
Numbers like 1.005 can’t be stored exactly in binary, so they may round down. For money, store whole units (paise or cents) as integers and format them only for display.
If you need help with an existing Perl codebase, see Perl development and maintenance.
Sources: perlfunc: substr; perlop: s/// and its modifiers; perlre: capture groups; perlfunc: sprintf; perlfaq4: why am I getting long decimals?.