Strings in Perl: quoted, interpolated and escaped
Understanding how strings work is important in every programming language, but in Perl they are part of the essence of the language. Especially if you consider that one of the acronyms of Perl is Practical Extraction and Reporting Language and for that you need to use lots of strings.
Strings can be placed either between single quotes ' or double quotes " and they have slightly different behavior.
Single quoted strings
If you put characters between single quotes ', then almost all the characters, except the single-quote itself ', are interpreted as they are written in the code.
my $name = 'Foo'; print 'Hello $name, how are you?\n';
The output will be:
Hello $name, how are you?\n
Double quoted strings
Strings placed between double quotes " provide interpolation (other variables embedded in the string will be replaced by their content), and they also replace the special escape sequences such as \n by a real newline and \t by a real tab.
my $name = 'Foo'; my $time = "today"; print "Hello $name,\nhow are you $time?\n";
The output will be
Hello Foo, how are you today?
Note, there is a \n right after the comma in the string and another one at the end of the string.
For simple strings such as 'Foo' and "today" that have no $, @, and \ characters in them, it does not matter how they are quoted.
The next two lines have the exact same result:
$name = 'Foo'; $name = "Foo";
Interpolating variables followed by other letters
In the following example we would like to print "Mb" immediately after the value that is in the variable.
examples/interpolation_speed.pl
my $speed = 100; print "The download speed is $speedMb\n";
We expected:
The download speed is 100Mb
but we get:
The download speed is
because Perl looks for the variable called $speedMb
If we have use strict enabled, as should always:
examples/interpolation_speed_strict.pl
use strict; use warnings; my $speed = 100; print "The download speed is $speedMb\n";
then we would get a compilation error:
Global symbol "$speedMb" requires explicit package name (did you forget to declare "my $speedMb"?) at interpolation_speed_strict.pl line 6. Execution of interpolation_speed_strict.pl aborted due to compilation errors.
The way to handle this case is to wrap the real variable name in curly braces:
examples/interpolation_speed_strict_fixed.pl
use strict; use warnings; my $speed = 100; print "The download speed is ${speed}Mb\n";
E-mail addresses
As @ also interpolates in double quoted strings, writing e-mail addresses needs a little more attention.
In single quotes @ does not interpolate.
In double quotes this code will generate an error: Global symbol "@bar" requires explicit package name at ... line ... and a warning: Possible unintended interpolation of @bar in string at ... line ...
The latter might be the one that provides the better clue what is really the problem.
use strict; use warnings; my $broken_email = "foo@bar.com";
This code, on the other hand, having the e-mail address in single quotes, will work.
use strict; use warnings; my $good_email = 'foo@bar.com';
What if you need both the interpolation of scalar variables but you want to include at marks @ in the string?
use strict; use warnings; my $name = 'foo'; my $good_email = "$name\@bar.com"; print $good_email; # foo@bar.com
You can always escape the special characters, in this case the at-mark @ by using the so-called escape character which is the back-slash \ character.
Embedding dollar $ sign in double quoted strings
In a similar way if you'd like to include a $ sign in an otherwise double-quoted string you can escape that too:
use strict; use warnings; my $name = 'foo'; print "\$name = $name\n";
Will print:
$name = foo
Escaping the escape character
There are rare cases when you'd like to include a back-slash character in a string. If you put a back-slash \ in a double-quoted string, Perl will think you want to escape the next character and do its magic.
Don't worry though. You can tell Perl to stop that by escaping the escape character:
You just put another back-slash in front of it:
use strict; use warnings; my $name = 'foo'; print "\\$name\n";
\foo
I know this escaping the escape character is a bit strange, but this is basically how it works in every other language as well.
If you'd like to understand this whole escaping business, try something like this:
print "\\\\n\n\\n\n";
see what does that print:
\\n \n
and try to explain it to yourself.
Escaping double quotes
We saw that you can put scalar variables in double-quoted strings but you can also escape the $ sign.
We saw how you can use the escape character \ and how you can escape that too.
What if you'd like to print a double quote in a double-quoted string?
This code has a syntax error:
use strict; use warnings; my $name = 'foo'; print "The "name" is "$name"\n";
when Perl sees the double-quote just before the word "name" it thinks that was the end of the string and then it complains about the word name being a bareword.
You might have already guessed, we need to escape the embedded " character:
use strict; use warnings; my $name = 'foo'; print "The \"name\" is \"$name\"\n";
This will print:
The "name" is "foo"
This works, but it is quite hard to read.
qq, the double-q operator
That's where you can use qq or the double-q operator:
use strict; use warnings; my $name = 'foo'; print qq(The "name" is "$name"\n);
For the untrained eyes, the qq() might look like a function call, but it is not. qq is an operator and you'll see in a second what else it can do, but first let me explain this.
We replace the double-quotes " that used to surround the string by the parentheses of the qq operator. This means the double-quotes are not special any more in this string, so we don't need to escape them. That makes the code a lot more readable. I'd even call it beautiful, if I did not fear the wrath of the Python programmers.
But what if you would like to include parentheses in your string?
use strict; use warnings; my $name = 'foo'; print qq(The (name) is "$name"\n);
No problem. As long as they are balanced (that is, having the same number of opening (, and closing ) parentheses, and always having the opening parentheses before the corresponding closing parentheses) Perl can understand it.
I know. You'll want to break it now, by putting a closing before the opening:
use strict; use warnings; my $name = 'foo'; print qq(The )name( is "$name"\n);
Indeed, Perl will give you a syntax error about "name" being a bareword. Perl can't understand everything, can it?
You could, of course, escape the parentheses in the string\) and \(, but we were down that rabbit hole already. No thank you!
There must be a better way!
Do you remember, I wrote qq is an operator and not a function? So it can do tricks, right?
What if we replaced the parentheses around our string by curly braces? {}:
use strict; use warnings; my $name = 'foo'; print qq{The )name( is "$name"\n};
That works and prints the string as we meant:
The )name( is "foo"
(even though I have not idea why would I want to print something like that...)
Then the guy from the second row raises his hand, and asks what if you want both parentheses and curly braces in your string, and you want them imbalanced?
You mean like this, right?
use strict; use warnings; my $name = 'foo'; print qq[The )name} is "$name"\n];
printing this:
The )name} is "foo"
... there must be a use for the square brackets too, right?
q, the single-q operator
Similar to qq there is also an operator called q. That too allows you select the delimiters of your string, but it works as a single quote ' works: It does NOT interpolate variables.
use strict; use warnings; print q[The )name} is "$name"\n];
prints:
The )name} is "$name"\n
Published on 2013-05-15