שיבוץ#
מחרוזות במרכאות כפולות, here-docs, תבניות regex, ההחלפה s/.../.../ ו־qq// כולם משבצים: הם מרחיבים משתנים ורצפי escape מסוימים במקום. מחרוזות במרכאות יחידות, q// ותבנית הצד־השמאלי של tr/.../.../ אינם. ידיעה אילו מבנים משבצים ואילו צורות בדיוק מורחבות היא אחד הפריטים השימושיים ביותר בידע Perl.
my $name = "Alice";
my @nums = (1, 2, 3);
"hello, $name" # "hello, Alice"
'hello, $name' # 'hello, $name' - single quotes don't interpolate
"@nums in a string" # "1 2 3 in a string"
"\$name is $name" # "$name is Alice"
מה משבץ#
בתוך "" (וההקשרים הדמויי־מרכאות־כפולות האחרים), Perl מרחיב בדיוק שתי צורות של משתנה:
$name # scalar - the simple form
@list # array - joined by $" (one space by default)
בתוספת צורות המנוי בסוגריים־מרובעים־ומסולסלים המורכבות על גביהן:
$arr[0] # one element of @arr
$h{key} # one value from %h
$ref->[0] # via array ref
$ref->{key} # via hash ref
@arr[1, 2] # array slice
@h{qw(a b)} # hash slice
שימו לב שהאשים שלמים אינם משבצים:
"hash is %h" # "hash is %h" - literal '%' is fine, '%h' is NOT magical
אם אתם רוצים האש מוטל לתוך מחרוזת, פרמטו אותו במפורש עם Data::Dumper או עם join ידני.
מה לא משבץ#
&sub # function calls don't interpolate
sub_with_args($x) # neither do calls with arguments
$h->method # method calls don't interpolate
$obj->{a} + 1 # arithmetic doesn't interpolate
$arr[0+1] # this DOES interpolate as $arr[0+1] - subscripts allow expressions
"\u\L$name" # case-modifying escapes - these DO interpolate
"\x{2603}" # numeric escapes - DO interpolate (a snowman)
כלל האצבע: משתנים והמנויים שלהם משבצים; קריאות פונקציה/מתודה וחשבון על גביהם אינם. כשאתם רוצים ביטוי משובץ, ראו את המבנים @{[ ... ]} ו־${\ ... } למטה.
הסוגריים ${name}#
סוגריים מסולסלים סביב שם משתנה מבהירים היכן השם מסתיים:
my $who = "Larry";
"${who}speak" # "Larryspeak"
"$whospeak" # "" with warning: $whospeak is uninitialised
"${who}::sub" # "Larry::sub"
"$who::sub" # the variable $who::sub from package who - bug
ללא הסוגריים, Perl חמדן: $whospeak נקרא כמזהה אחד, $who::sub נקרא כשם מוסמך־חבילה. הסוגריים מאלצים את הפרסר לעצור ב־}.
זו אינה אותה צורת־סוגריים כמו מנוי האש:
"$h{key}" # hash element - what most people mean
"${h}{key}" # hash element in a different parse path - same result
"${h{key}}" # also the same
"${\(\$h{key})}" # the absurd "interpolate an expression" form
הסוגריים ${name} משמשים בעיקר למקרה ההבהרה (שם שאחריו תווים אלפאנומריים שאחרת היו נאכלים), לא לגישת האש.
הצורות @{...} ו־${...} של deref־עם־סוגריים#
כשאתם רוצים לבצע dereference למשהו בתוך מחרוזת, צורת הסוגריים מאפשרת לביטוי ה־deref להיות שרירותי:
my $config = { users => ['Alice', 'Bob'] };
"users: @{ $config->{users} }" # "users: Alice Bob"
"users: $config->{users}" # "users: ARRAY(0x...)" - wrong; whole arrayref stringified
"users: @$config->{users}" # parse error / wrong
The @{ EXPR } form deref’s EXPR as an array. The braces are required because the deref target is an expression, not a plain variable. @$config->{users} doesn’t parse the way intended
@$configwould deref$configas an array, and->{users}is a hash-element access on what’s left.
אותו דבר עבור ${ EXPR } (deref סקלר) ו־%{ EXPR } (deref ההאש, המחזיר רשימה שטוחה, שימושי לעיתים רחוקות בשיבוץ).
@{[ expr ]} - שבצו כל ביטוי רשימה#
כדי לשבץ את תוצאת ביטוי שרירותי, עטפו אותו ב־@{[ ... ]}:
my $name = "World";
print "hello, @{[ uc $name ]}!\n"; # "hello, WORLD!"
print "found @{[ scalar @hits ]} matches\n"; # interpolate a count
print "users: @{[ join ', ', @users ]}\n"; # interpolate a join
המנגנון: [ ... ] בונה הפניית מערך אנונימית שתוכנה הוא ערך הקשר־הרשימה של הביטוי; @{ ... } אז עושה deref ל־arrayref הזה בחזרה לרשימה, המשתבצת כפי שרשימה משתבצת (מחוברת על־ידי $").
זהו העקיפה הקנונית עבור ”I want a function call inside a double-quoted string“. החלופה היא שרשור:
print "hello, " . uc($name) . "!\n"; # equivalent
הצורה @{[ ... ]} צפופה יותר כשיש מספר שיבוצים; שרשור ברור יותר כשיש רק אחד. בתבניות עם שדות רבים, printf או sprintf בדרך כלל ברורים עוד יותר:
printf "found %d matches\n", scalar @hits;
השתמשו ב־@{[ ... ]} כשאתם באמת רוצים ביטוי Perl באמצע מחרוזת והחלופות מכוערות יותר.
${\ expr } - שבצו ביטוי סקלר#
המקבילה הסקלרית של @{[ ... ]}:
print "answer: ${\ 6 * 7 }\n"; # "answer: 42"
print "ts: ${\ scalar localtime }\n"; # "ts: Mon Apr 27 ..."
\ EXPR יוצר הפניה לערך הסקלרי של EXPR; ${ ... } עושה לו deref. התוצאה היא ערך אחד, המשובץ כסקלר.
ברוב המקרים הצורה @{[ ... ]} אחידה יותר - היא עובדת עבור הקשר סקלר ורשימה כאחד. ${\ ... } ברורה לעיתים כשאתם רוצים ספציפית הקשר סקלר:
"got @{[ items() ]} items" # items() called in LIST context
"got ${\ items() } items" # items() called in SCALAR context
דו־משמעות מנוי־האש בתבניות#
בתוך תבנית regex (שהיא דמוית־מרכאות־כפולות), הפרסר צריך לנחש אם $foo[bar] פירושו ”interpolate $foo[bar] (one element of @foo)“ או ”interpolate $foo and then match a character class [bar]“:
my @foo = ('hi');
$x =~ /$foo[abc]/ # @foo exists - parsed as $foo[abc] (one element)
$x =~ /$foo[abc]/ # @foo doesn't exist - parsed as $foo + char class
ההבהרה היא צורת הסוגריים:
$x =~ /${foo}[abc]/ # $foo + character class [abc]
$x =~ /$foo[5]/ # element 5 of @foo
$x =~ /\Q$foo\E[abc]/ # $foo (literal) + character class
המצטט \Q...\E משבית פרשנות מטה־תווים בתוך תחומו, מה שהוא התיקון הנקי ביותר כשהמשתנה הוא קלט משתמש.
Heredocs#
Heredocs הם דמויי־מרכאות־כפולות אלא אם הסמן הוא במרכאות יחידות:
my $msg = <<EOM;
Hello, $name!
The hash is %h.
EOM
# "Hello, Alice!\nThe hash is %h.\n" - $name interpolated, %h literal
my $msg = <<'EOM';
Hello, $name!
EOM
# "Hello, $name!\n" - single-quoted marker disables interpolation
Heredocs מוזחים (Perl 5.26+) מתעלמים מרווח מוביל עד לרצף הקצר ביותר בכל שורה:
my $msg = <<~EOM;
Hello, $name!
EOM
# "Hello, Alice!\n" - leading " " stripped from every line
הצורה ~ מועדפת בקוד מודרני; הצורה הלא־מוזחת מכוערת בתוך לולאות וגופי מתודה.
דוגמה אמיתית: בניית HTML בבטחה#
my @items = ('Apples', 'Bananas', 'Cherries');
my $html = <<~HTML;
<ul>
@{[ map { " <li>$_</li>" } @items ]}
</ul>
HTML
ה־map מחזיר רשימה של מחרוזות <li>...</li>; @{[ ... ]} משבץ אותן; ה־$" המשתמע הוא רווח יחיד, ונותן:
<ul>
<li>Apples</li> <li>Bananas</li> <li>Cherries</li>
</ul>
כדי לקבל שורות חדשות בין הפריטים, הגדירו $" באופן מקומי:
my $html = do {
local $" = "\n";
<<~HTML;
<ul>
@{[ map { " <li>$_</li>" } @items ]}
</ul>
HTML
};
או חברו במפורש:
my $li = join "\n", map { " <li>$_</li>" } @items;
my $html = "<ul>\n$li\n</ul>\n";
ה־join המפורש בדרך כלל ברור יותר עבור תבניות לא־טריוויאליות. הצורה @{[ ... ]} מצדיקה את מקומה כשהתבנית היא בעיקר טקסט מילולי עם חישוב משובץ אחד או שניים.
מה המשתנה המיוחד $" שולט בו#
מפריד הרשימה בשיבוץ:
my @x = (1, 2, 3);
print "x = @x\n"; # "x = 1 2 3" - default $" is " "
local $" = ", ";
print "x = @x\n"; # "x = 1, 2, 3"
local $" = "\n ";
print "items:\n @x\n"; # "items:\n 1\n 2\n 3"
$" הוא הדרך הקנונית לשלוט באופן שמערכים משבצים מבלי לכתוב מחדש את המחרוזת. ראו מצב מטפל קובץ והדפסה עבור משפחת משתני המפריד.
ראו גם#
הפניות - צורת ה־deref
@{ EXPR }ומה ה־\ב־${\ ... }עושה.$"- מפריד הרשימה עבור שיבוץ מערך.$,,$\,$/- משתני המפריד הקשורים עבורprintוקלט.-
the explicit format-string alternative when the template is mostly punctuation.