לעתים יש צורך ליצור מחרזות שמתפרסת על מספר שורות. כפי שמקובל בפרל, יש לכך מספר פתרונות. אחד הפתרונות הנפוצים הוא שימוש במבנה שנקרא here-document.

here-document מאפשר לך ליצור מחרוזת שמתפרסת על מספר שורות ושומרת על הרווחים ועל סופי השורות. אם תריץ את הקוד הבא הוא ידפיס בדיוק את מה שאתה רואה החל מהמילה Dear עד השורה לפני ההופעה השניה של END_MESSAGE.

here document ללא אינטרפולציה

#!/usr/bin/perl
use strict;
use warnings;

my $name = 'Foo';

my $message = <<'END_MESSAGE';
Dear $name,

this is a message I plan to send to you.

regards
  the Perl Maven
END_MESSAGE

print $message;

פלט:

Dear $name,

this is a message I plan to send to you.

regards
  the Perl Maven

מחרוזת here document עם שני סימני 'קטן מ-' << ומיד אחריהם מחרוזת שרירותית שהופכת לסימן הסיום של ה-here-document,אחריה יש נקודה פסיק ; שמסמן את סוף הפקודה. זה קצת מוזר כיוון שלמעשה היא אינה מסתיימת כאן. התוכן של מחרוזת ה-here-document מתחיל רק שורה אחרי הנקודה-פסיק, (במקרה שלנו עם המילה "Dear"), וממשיך עד שפרל מוצאת את סימן סיום הפקודה השרירותי שנבחר. במקרה שלנו המחרוזת END_MESSAGE.

אם כבר ראית שימוש של here-document בקוד אז ייתכן שאתה מופתע מהשימוש בגרש בודד מסביב ל-END_MESSAGE הראשון. אני סבור שאם תמצא דוגמאות של here-document באינטרנט, או מאחורי חומות האש של מקום העבודה שלך, קרוב לוודאי שתמצא את החלק הפותח ללא גרשיים כלשהם. כך:

my $message = <<END_MESSAGE;
...
END_MESSAGE

כשכותבים כך זה אותו דבר כמו לכתוב את END_MESSAGE בגרשיים כפולים כמו בדוגמה הבאה, אך צורת כתיבה זו נחשבת מיושנת והיא תוצא משימוש בגרסה 5.20. אין להשתמש בצורה זו! אין להשתמש במחרוזות here document ללא גרשיים מסביב להגדרת מחרזות הסיום.:

my $message = <<"END_MESSAGE";
...
END_MESSAGE

אם אתה כבר מכיר את ההבדל בין גרשיים בודדים וגרשיים כפולים quotes בפרל, אז לא תהיה זו הפתעה לגלות שב-here-document הם מתנהגים באותה צורה. ההבדל היחיד הוא שהגרשיים הם מסביב סימן הסיום ולא סביב המחרוזת עצמה. אם אין גרשיים, פרל מניחה כברירת מחדל שהתתנהגות היא של גרשיים כפולות.

אם תחזור ותסתכל בדוגמה הראשונה, ודאי תשים לב שהיה לנו את $name כחלק מה- here-document והוא גם נותר כחלק מהפלט. הסיבה לכך היא שפרל לא ניסתה מלא את המקום עם תוכנו של המשתנה $name . אפילו לא היינו צריכים להגדיר את המשתנה בקוד. אפשר לנסות להריץ את הקוד אפילו בלי השורהmy $name = 'Foo'; .

אינטרפולציה של here document

בדוגמה הבאה נשים את סימן הסיום בגרשיים כפולות ולכן תתבצע אינטפולציה של המשתנה $name :

use strict;
use warnings;

my $name = 'Foo';
my $message = <<"END_MSG";
Hello $name,

how are you?
END_MSG

print $message;

התוצאת של הרצת הקוד היא:

Hello Foo,

how are you?

אזהרה: יש לדייק במחרוזת הסיום

רק עוד הערה. יש לוודא שמחרוזת הסיום מועתקת במדויק כפי שהיא נכתבה בהתחלה. ללא רווחים לפניה או אחריה. אחרת פרל לא תזהה אותה ותחשוב שה-here-document עוד לא הסתיים. המשמעות של זה היא שאי אפשר לכתוב את מחרוזת הסיום באינדנטציה שמתאימה לשאר הקוד. או אולי בכל זאת אפשר?

מחרוזות here document ואינדנציה של קוד

אם ה-here-document צריך להיות במקום שבו בדרך כלל נוסיף רווחי אינדנטציה לקוד, אז יש לנו שתי בעיות:

#!/usr/bin/perl
use strict;
use warnings;

my $name = 'Foo';
my $send = 1;

if ($send) {
    my $message = <<"END_MESSAGE";
        Dear $name,
    
        this is a message I plan to send to you.
    
        regards
          the Perl Maven
END_MESSAGE
    print $message;
}

בעיה אחת היא הבעיה שהזכרתי קודם, מחרוזת הסיום חייבת להיות זהה למחרוזת בתחילת ה-here-document, ולכן אי אפשר להוסיף רווחים לפניה.

הבעיה השניה היא שבפלט יופיעו כל הרווחים הנוספים בתחילת כל שורה.

        Dear Foo,
    
        this is a message I plan to send to you.
    
        regards
          the Perl Maven

ניתן לפתור את הבעיה הראשונה, רווחים במחרוזת הסיום, על ידי שימוש במחרוזת שכבר כוללת מספיק רווחים בתחילתה: (אני משתמש כאן ב-4 רווחים אמיתיים, כיוון שטאבים לא נראים טוב במאמר, אך הם עובדים בקוד אמיתי): אם אתה מחסידי האינדטציה על ידי טאבים).

    my $message = <<"    END_MESSAGE";
       ...
    END_MESSAGE

ניתן להסיר את הרווחים הנוספים בטקסט עצמו על ידי שימוש בחילוף בעת ההצבה.

    (my $message = <<"    END_MESSAGE") =~ s/^ {8}//gm; 
        ...
    END_MESSAGE

בחילוף אנחנו מחליפים 8 רווחים מקדימים במחרוזת הריקה. אנחנו משתמשים בשני מגדירים: /m משנה את ההתנהגות של ^ כך שבמקום למצוא התאמה בתחילת המחרוזת, תימצא התאמה בתחילת השורה. /g אומר להחלפה לפעול גלובאלית, כלומר לחזור על ההחלפה כמה פעמים שאפשר.

ביחד הם גורמים חילוף למחוק 8 רווחים מקדימים מכל שורה שמשתנה בצד שמאל של =~. בצד שמאל שמנו את ההצבה בסוגריים כיוון שהקדימות של סימן ההצבה (=) היא גבוהה יותר מהקדימות של הביטוי הרגולרי =~. בלי הסוגריים, פרל קודם תציב את התוכן של ה-here-document במשתנה $message ואז היא תנסה להריץ את החילוף על ה-here-document עצמו, מה שיגרום לשגיאת קומפילציה:

Can't modify scalar in substitution (s///) at programming.pl line 9, near "s/^ {8}//gm;"

שימוש ב- q או ב- qq

לאחר כל ההסבר הזה, אני לא בטוח שאני באמת רוצה להמליץ על שימוש ב-here-documents. במקרים רבים אני מעדיף להשתמש ב- qq או ב- q operator. תלוי אם אני רוצה מחרוזת עם אינטרפולציה או בלי אינטרפולציה:

#!/usr/bin/perl
use strict;
use warnings;

my $name = 'Foo';
my $send = 1;

if ($send) {
    (my $message = qq{
        Dear $name,
    
        this is a message I plan to send to you.
    
        regards
          the Perl Maven
        }) =~ s/^ {8}//mg;
    print $message;
}