I am writing a script in Perl and have a question about Perl's foreach
construct.
It appears that if you change one of the loop variables it changes in the actual array. Is this in fact the case, or have I done something completely wrong?
I want to change a string like abc.abc#a
to abc_abc_a
(underscores for non alpha-numeric characters), but I need to preserve the original value in the array for later use.
I have code that looks something like this:
@strings = ('abc.abc#a', 'def.g.h#i');
foreach my $str (@strings){
$str =~ s/[^0-9A-Za-z]/_/g;
print $str, "\n"; #Actually I use the string to manipulate files.
}
I could solve the problem by doing the following:
@strings = ('abc.abc#a', 'def.g.h#i');
foreach my $str (@strings){
my $temp = $str; #copy to a temporary value
$temp =~ s/[^0-9A-Za-z]/_/g;
print $temp, "\n"; #$str remains untouched...
}
but is there a more efficient way to accomplish this?
Thank you very much!
The basic form of the foreach statement is. foreach var (list) block of statements. The variable var will take on each value stored in list in turn, executing the block of statements and continuing on to the next value in the list.
In many programming languages you use the break operator to break out of a loop like this, but in Perl you use the last operator to break out of a loop, like this: last; While using the Perl last operator instead of the usual break operator seems a little unusual, it can make for some readable code, as we'll see next.
A foreach loop is used to iterate over a list and the variable holds the value of the elements of the list one at a time. It is majorly used when we have a set of data in a list and we want to iterate over the elements of the list instead of iterating over its range.
You're not crazy; this is normal behaviour. See perldoc perlsyn under Foreach loops:
If any element of LIST is an lvalue, you can modify it by modifying VAR inside the loop. Conversely, if any element of LIST is NOT an lvalue, any attempt to modify that element will fail. In other words, the "foreach" loop index variable is an implicit alias for each item in the list that you're looping over.
Other loop iterators such as map have similar behaviour:
map BLOCK LIST map EXPR,LIST
...
Note that $_ is an alias to the list value, so it can be used to modify the elements of the LIST. While this is useful and supported, it can cause bizarre results if the elements of LIST are not variables. Using a regular "foreach" loop for this purpose would be clearer in most cases. See also "grep" for an array composed of those items of the original list for which the BLOCK or EXPR evaluates to true.
You could rewrite your code this way, which would at least save you from adding an extra line:
my @strings = ('abc.abc#a', 'def.g.h#i');
foreach my $str (@strings){
(my $copy = $str) =~ s/[^0-9A-Za-z]/_/g;
print $copy, "\n";
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With