13.2. Manipulating a Substring with substr
The substr operator works with only a part of a larger string. It looks like this:
$part = substr($string, $initial_position, $length);
It takes three arguments: a string value, a zero-based initial position (like the return value of index), and a length for the substring. The return value is the substring:
my $mineral = substr("Fred J. Flintstone", 8, 5); # gets "Flint" my $rock = substr "Fred J. Flintstone", 13, 1000; # gets "stone"
As in the previous example, if the requested length (1000 characters, in this case) goes past the end of the string, there'll be no complaint from Perl, but you get a shorter string than you might have. If you want to be sure to go to the end of the string, however long or short it may be, omit that third parameter (the length) like this:
my $pebble = substr "Fred J. Flintstone", 13; # gets "stone"
The initial position of the substring in the larger string can be negative, counting from the end of the string (that is, position -1 is the last character). In this example, position -3 is three characters from the end of the string, which is the location of the letter i:
] This is analogous to what you saw with array indices in Chapter 3. As arrays may be indexed from 0 (the first element) upward or from -1 (the last element) downward, substring locations may be indexed from position 0 (at the first character) upward or from position -1 (at the last character) downward.
my $out = substr("some very long string", -3, 2); # $out gets "in"
index and substr work well together. In this example, we can extract a substring that starts at the location of the letter l:
my $long = "some very very long string"; my $right = substr($long, index($long, "l") );
Now here's something really cool: The selected portion of the string can be changed if the string is a variable:[*]
my $string = "Hello, world!"; substr($string, 0, 5) = "Goodbye"; # $string is now "Goodbye, world!"
The assigned (sub)string doesn't have to be the same length as the substring it's replacing. The string's length is adjusted to fit. If that isn't cool enough to impress you, you could use the binding operator (=~) to restrict an operation to work with part of a string. This example replaces fred with barney wherever possible within the last twenty characters of a string:
substr($string, -20) =~ s/fred/barney/g;
We've never needed that functionality in any of our own code, and chances are you'll never need it either. But it's nice to know that Perl can do more than you'll need, isn't it?
Much of the work that substr and index do could be done with regular expressions. Use those where they're appropriate. substr and index are often faster since they don't have the overhead of the regular expression engine: they're never case-insensitive, they have no metacharacters to worry about, and they don't set any of the memory variables.
Besides assigning to the substr function (which can look a little weird at first glance), you can use substr in a more traditional manner with the four-argument version, in which the fourth argument is the replacement substring:
my $previous_value = substr($string, 0, 5, "Goodbye");
The previous value comes back as the return value, though you can use this function in a void context to discard it.