use Encode (); use Encode::Detect (); # DEEPLY decode provided arguments to UTF-8 sub to_utf8 { my @args = @_; return if !@args; for my $arg (@args) { my $rt = ref $arg; if ( !$rt ) { $arg = _scalar_to_utf8($arg); } elsif ( $rt eq 'ARRAY' ) { $arg = _array_to_utf8($arg); } elsif ( $rt eq 'HASH' ) { # do NOT convert KEYS, only VALUES! #$arg = _hash_values_to_utf8($arg); $arg = _hash_to_utf8($arg); # ^ hmm, NOT! we need it all :( } # FIXME: what about the other cases?! } return @args == 1 ? $args[0] : @args; } sub _array_to_utf8 { my ($ar) = @_; return [ map { to_utf8($_) } @{$ar} ]; } sub _hash_to_utf8 { my ($hr) = @_; my %ret; while ( my ( $k, $v ) = each %{$hr} ) { $ret{ _scalar_to_utf8($k) } = to_utf8($v); } return \%ret; } sub _hash_values_to_utf8 { my ($hr) = @_; my %ret; while ( my ( $k, $v ) = each %{$hr} ) { $ret{$k} = to_utf8($v); } return \%ret; } sub _scalar_to_utf8 { my ($str) = @_; return $str if Encode::is_utf8($str); eval { $str = Encode::decode_utf8($str) }; if ($@) { $str = Encode::encode( 'Detect', $str ); } return $str; }