Saved has asked for the wisdom of the Perl Monks concerning the following question:

I have looked around for a slick way of removing nulls from an array. I could use a loop, but thought someone might have a better way. "map" is described as doing something to each element, and "tr" will remove with d option. Is there a way to get something like this to work? @CLEANED =~ map(tr/\000//d, @EMPLOYEES); Thanx

Replies are listed 'Best First'.
Re: Remove nulls, or other Chars
by moritz (Cardinal) on Apr 01, 2011 at 13:57 UTC
    There is a way indeed. Your approach doesn't work because tr/// returns the number of transliterations (or in your case, removals), and map collects return values. So you need to actually return $_
    use strict; use warnings; use Data::Dumper; $Data::Dumper::Useqq = 1; my @a = ("a\000b\000c", "foo\000bar"); print Dumper \@a; my @cleaned = map {tr/\000//d; $_ } @a; print Dumper \@cleaned;

    Please note that a common cause for null bytes is the use of UTF-16; if that's the case, don't remove the null bytes, but decode the strings.

      Thank You for explaination & Solution
Re: Remove nulls, or other Chars
by BrowserUk (Patriarch) on Apr 01, 2011 at 13:58 UTC

    Almost right. Try:

    @CLEANED = map{ tr/\000//d; $_ } @EMPLOYEES;

    But do note that will also modify @EMPLOYEES. If you don't want that, you could do:

    @cleaned = @employees; tr/\000//d for @cleaned;

    And if you're happy to clean employees in place, omit the copy and operate directly on @employees.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      This worked gr8, Thanx
Re: Remove nulls, or other Chars
by ikegami (Patriarch) on Apr 01, 2011 at 19:39 UTC

    I could use a loop, but thought someone might have a better way.

    Impossible. You can't visit each string in the array without looping over the array. Same goes for each character of those strings. The type of loop may vary, that's all.

    Here are some ways:

    • my @CLEANED = map { ( my $s = $_ ) =~ tr/\000//d; $s } @EMPLOYEES;
    • # Requires Perl 5.14 my @CLEANED = map { s/\000//r } @EMPLOYEES;
    • map { tr/\000//d } my @CLEANED = @EMPLOYEES;
    • my @CLEANED = @EMPLOYEES; tr/\000//d for @CLEANED;
    • use List::MoreUtils qw( apply ); my @CLEANED = apply { tr/\000//d } @EMPLOYEES;
    • use Algorithm::Loops qw( Filter ); my @CLEANED = Filter { tr/\000//d } @EMPLOYEES;

    I'd avoid the following because it "cleans" both @EMPLOYEES and @CLEANED:

    my @CLEANED = map { tr/\000//d; $_ } @EMPLOYEES; # XXX

    Update: I definitely avoid the snippet I originally posted as "I'd avoid", since it cleaned @EMPLOYEES and produced junk in @CLEANED. Fixed.