in reply to substr question

From the docs:
You can use the substr() function as an lvalue, in which case EXPR must itself be an lvalue. If you assign something shorter than LENGTH, the string will shrink, and if you assign something longer than LENGTH, the string will grow to accommodate it.

Essentially when using substr as an lvalue it remembers the offset and length into which the rvalue will be substituted. As you surmised, the length is updated to the length of the substitution in each case. This is natural and means that each successive substitution will fully replace the previous one.

And this is what we see in each of the cases you give in your example.:

$x = '1234'; for (substr($x,1,2)) { # lvalue offset and length start at (1 +,2) $_ = 'a'; print $x,"\n"; # becomes (1,1) -- prints 1a4, $_ = 'xyz'; print $x,"\n"; # becomes (1,3) -- prints 1xyz4 $x = '56789'; # no change (1,3) $_ = 'pq'; print $x,"\n"; # becomes (1,2) after pq is subbed int +o (1,3) -- prints 5pq9 }

Replies are listed 'Best First'.
Re^2: substr question
by johngg (Canon) on Aug 04, 2013 at 13:05 UTC

    I don't think it is a case of substr "remembering" the length and offset. I think it is more to do with the fact that $_ inside the for loop is an alias (effectively a reference) to each item in the list in turn; in this case just one item, the sub-string. Using a reference to the sub-string, the following code demonstrates that because it is being assigned to, the referenced sub-string will be of the length of the last assignment regardless of the fact that it was originally only two characters long. Remaking the reference each time keeps the length at two as you would expect.

    use strict; use warnings; use feature qw{ say }; my $str = q{1234}; my $ref = \ substr $str, 1, 2; show(); noRefReset( $_ ) for qw{ a xyz }; $str = q{56789}; show(); noRefReset( $_ ) for qw{ pq ghijkl st }; say q{-} x 18; $str = q{1234}; $ref = \ substr $str, 1, 2; show(); refReset( $_ ) for qw{ a xyz }; $str = q{56789}; show(); refReset( $_ ) for qw{ pq ghijkl st }; sub noRefReset { ${ $ref } = shift; show(); } sub refReset { ${ $ref } = shift; $ref = \ substr $str, 1, 2; show(); } sub show { printf qq{%-9s - %s\n}, $str, ${ $ref }; }

    The output.

    1234 - 23 1a4 - a 1xyz4 - xyz 56789 - 678 5pq9 - pq 5ghijkl9 - ghijkl 5st9 - st ------------------ 1234 - 23 1a4 - a4 1xyz - xy 56789 - 67 5pq89 - pq 5ghijkl89 - gh 5stijkl89 - st

    I hope this is of interest.

    Cheers,

    JohnGG

      Thank you JohnGG !

      Maybe that's the internal implement of substr's behavior when it is used in a for loop. Thank you for your detailed example. I do learn a lot from it.

Re^2: substr question
by lightoverhead (Pilgrim) on Aug 05, 2013 at 23:05 UTC

    Thank you!

    I hope perldoc can be as clear as you demonstrated!