The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
docs: |
    This function, like many in PHP, is really two functions.

    The first is the same as L<the tr operator|perlop/"tr">.
    And you really should use C<tr> instead of this function.

    The second is more complicated.

code: |
    sub _make_re_list
    {
        return qr/@{[ join '|', map quotemeta, @_ ]}/;
    }

    sub _strtr_pairs
    {
        my ( $string, $pairs ) = @_;
        my @alternates = reverse sort { length $a <=> length $b } keys %$pairs;

        # Exit quickly if we don't need to stay.
        return $string unless @alternates;

        my $regex = _make_re_list( @alternates );

        $string =~ s/($regex)/$pairs->{$1}/eg;
        
        return $string;
    }

    sub _strtr_tr
    {
        my ( $string, $from, $to ) = @_;

        # Exit quickly if we don't need to stay.
        return $string unless length $from;

        # Ignore excess characters
        if ( length $from != length $to )
        {
            if ( length $to > length $from ) {
                substr( $to, (length $from) ) = "";
            } elsif ( length $from > length $to ) {
                substr( $from, (length $to) ) = "";
            }
        }

        eval "\$string =~ tr/$from/$to/, 1" or die $@;

        return $string;
    }

    sub strtr
    {
        my ( $string, $from, $to ) = validate_pos( @_,
            STRING,
            STRING|HASHREF,
            {
                %{+STRING},
                optional => 1,
            },
        );

        if ( ref $from eq 'HASH' )
        {
            if ( not defined $to )
            {
                return _strtr_pairs( $string, $from );
            }
            else
            {
                croak "Parameter #3 to PHP::Strings::strtr ",
                    "present when it should not be in 2-argument form.";
            }
        }
        elsif ( defined $from and not defined $to )
        {
            croak "Parameter #3 to PHP::Strings::strtr missing from".
                " 3-argument form.";
        }
        else
        {
            return _strtr_tr( $string, $from, $to );
        }
    }