0

I have an array which contains n number of elements. So there might be chances the each element could have spaces in the beginning or at the end. So I want to remove the space in one shot. Here is my code snippet which is working and which is not working (The one which not working is able to trim at the end but not from the front side of the element).

Not Working:

....
use Data::Dumper;

my @a = ("String1", " String2 ", "String3 ");

print Dumper(\@a);

@a = map{ (s/\s*$//)&&$_}@a;

print Dumper(\@a);
...

Working:

...
use Data::Dumper;

my @a = ("String1", " String2 ", "String3 ");

print Dumper(\@a);

my @b = trim_spaces(@a);

print Dumper(\@b);

sub trim_spaces
{
    my @strings = @_;
    s/\s+//g for @strings;
    return @strings;
}
...

No idea whats the difference between these two.

If there is any better please share with me!!

0

2 Answers 2

6

Your "not working example" only removes spaces from one end of the string. The expression s/^\s+|\s+$//g will remove spaces from both ends.

You can improve your code by using the /r flag to return a modified copy:

@a = map { s/^\s+|\s+$//gr } @a;

or, if you must:

@a = map { s/^\s+|\s+$//g; $_ } @a;
Sign up to request clarification or add additional context in comments.

3 Comments

Note that in the version that doesn't use /r, the assignment back to @a is actually superfluous, since @a will be modified in-place.
@a = map { s/^\s+|\s+$//g; $_ } @a; makes no sense. If you remove the redundant statements, you get map { s/^\s+|\s+$//g } @a; which is better written as s/^\s+|\s+$//g for @a;. I think you were going for @a = map { (my $s = $_) =~ s/^\s+|\s+$//g; $s } @a;
You cannot use the return value of s/// directly as it is the number of replacements performed. Hence the ; $_ to return $_ again. Of course the r flag is by far the better solution. Or indeed the for loop, but sometimes that means storing into an intermediate variable.
3

This block has two problems:

{ (s/\s*$//)&& $_ }

The trivial problem is that it's only removing trailing spaces, not leading, which you said you wanted to remove as well.

The more insidious problem is the misleading use of &&. If the regex in s/// doesn't find a match, it returns undef; on the left side of a &&, that means the right side is never executed, and the undef becomes the value of the whole block. Which means any string that the regex doesn't match will be removed and replaced with a undef in the result array returned by map, which is probably not what you want.

That won't actually happen with your regex as written, because every string matches \s*, and s/// still returns true even if it doesn't actually modify the string. But that's dependent on the regex and a bad assumption to make.

More generally, your approach mixes and matches two incompatible methods for modifying data: mutating in place (s///) versus creating a copy with some changes applied (map).

The map function is designed to create a new array whose elements are based in some way on an input array; ideally, it should not modify the original array in the process. But your code does – even if you weren't assigning the result of map back to @a, the s/// modifies the strings inside @a in place. In fact, you could remove the @a = from your code and get the same result. This is not considered good practice; map should be used for its return value, not its side effects.

If you want to modify the elements of an array in place, your for solution is actually the way to go. It makes it clear what you're doing and side effects are OK.

If you want to keep the original array around and make a new one with the changes applied, you should use the /r flag on the substitutions, which causes them to return the resulting string instead of modifying the original in place:

my @b = map { s/^\s+|\s+$//gr } @a;

That leaves @a alone and creates a new array @b with the trimmed strings.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.