s/(old)/preserve_case("new", $1)/ieg; sub preserve_case { my ($to, $from) = @_; die "strings don't match in length" unless length($to) == length($from); my $mask = $from & (' ' x length($from)); return uc($to) | $mask; }