#!/usr/bin/perl use warnings; use strict; my %dictionary = (foo => 'bar', baz => 'w00t'); sub replace { my $str = shift; $str =~ m[(<[^>]+>)?([^<]+)(]+>)?(.*)]; # the key should never contain '<' my $key = $2 . $4; my @tags = ($1, $3); my $length = length $2; $key =~ s[$_][$dictionary{$_}] for keys %dictionary; if (grep $_, @tags) { # return tags to replaced string substr $key, $length, 0, $tags[1]; substr $key, 0, 0, $tags[0]; } return $key; } use Test::More; is replace('baz'), 'w00t'; is replace('foo'), 'bar'; is replace('foo'), 'bar'; done_testing();