קיבוץ ומונים#
בסוף הפרק הזה תוכלו לחזור על תבנית הוראות לאורך רשימת ערכים, להשתמש בצורות * ו־[…] של מונה חזרות, ולכתוב רשומות עם קידומת אורך תיאוריות־עצמן באמצעות הוראת /.
A bare repeat count applies to one directive letter: C4 packs four bytes. The moment the repeating unit is more than one directive
”pack a short and two bytes, many times“ - you need a group.
() - קבוצה היא תת־תבנית#
סוגריים אוספים רצף של הוראות כך שמונה חזרות או מתאם endianness חל על השלם. השוו:
pack "C S C S C S", @a, @b, @c, @d, @e, @f # repeat by hand
pack "(CS)3", @a, @b, @c, @d, @e, @f # same thing, grouped
pack "(CS)*", @pairs # repeat as often as values last
לקבוצה אין עלות בתים משלה - היא מנגנון תחבירי. האורך הארוז הכולל הוא מה שההוראות בתוכה היו מייצרות ללא הסוגריים.
קיבוץ עם endianness#
השימוש המעשי הבודד ביותר של קבוצה - תת־מבנה שכל מספר שלם בו חולק סדר בתים אחד:
my $rec = pack "(l s s)<", $id, $x, $y;
# same as "l<s<s<"
ה־< מתפזר לכל הוראה מסודרת־בתים בתוכה, כולל קבוצות מקוננות. הוראות שאינן מקבלות מתאם סדר־בתים (כמו C, a, Z) אינן מושפעות בשקט.
מוני חזרות במלואם#
אחרי כל הוראה או קבוצה, אפשר לכתוב:
צורה | משמעות |
|---|---|
| החילו את ההוראה/קבוצה |
| החילו כל עוד נשארים ערכים. עבור |
| זהה ל־ |
| מונה חזרות הוא אורך הבתים הארוז של התבנית בסוגריים |
צורת ה־[template] היא הכלי לביטוי ״כמה בתים שלוקח foo״:
pack "x[L]" # skip 4 bytes (sizeof a packed long)
pack "x[d]" # skip 8 bytes (sizeof a packed double)
pack "a[Q]" # one string 8 bytes wide
היא שימושית במיוחד ליישור (ראו את פרק המיקום) ולתבניות שרוחביהן חייבים לעקוב אחר הגודל תלוי־הפלטפורמה של מספר שלם native:
pack "a[l!]", $native_long_buf # room for one native long
* הוא לכל־קבוצת־ערכים, לא ״בלע הכל״#
* בודד סופר ״ערכים נותרים״ עבור ההוראה הזו. שני A* ברצף אינם מתחרים:
pack "A*A*", "hello", "world" # "helloworld"
ה־A* הראשון אורז את כל "hello"; השני אורז את כל "world". כל * צורך ערך אחד מהרשימה, באורך המלא של אותו ערך. זה הכלל הכללי: כל הוראה מתאימה לפיסת נתונים אחת, יהיה מונה החזרות שלה אשר יהיה.
הוראת ה־/ - אורך ונתונים יחד#
פורמטים של חוט שומרים תכופות מונה מיד לפני הדבר הנספר: ״אורך 2 בתים, ואז כך וכך בתים של payload״. הוראת / קושרת את השניים לצעד אחד.
ב־pack: length-item/sequence-item#
כתבו שתי הוראות מופרדות בקו נטוי. הראשונה אורזת את האורך; השנייה אורזת את ה־payload. pack מחשב את האורך עבורכם:
my $msg = pack "n/a*", "hello, world";
# "\x00\x0chello, world"
# ^^^^^^^^ big-endian 16-bit length = 12
# ^^^^^^^^^^^ the payload itself
ה־length-item עשוי להיות כל הוראה מספרית - C, n, N, w, S<, וכן הלאה - או הוראת מחרוזת כגון A4 כאשר הפרוטוקול כותב את האורך כ־ASCII:
my $buf = pack "A4/A*", "Humpty-Dumpty";
# "13 Humpty-Dumpty" - 4-char ASCII length, then the string
ב־unpack: /item#
צורת ה־unpack פשוטה יותר: / חשוף לפני הפריט. המונה נלקח מהוראת המספר השלם האחרונה:
my ($payload) = unpack "n/a*", $msg; # "hello, world"
קריאת התבנית הזו: ״קראו מספר שלם n, קראו לו L; אז קראו L בתים כמחרוזת בסגנון a*.״ האורך עצמו אינו מופיע ברשימת הפלט.
הטעות הנפוצה: A* אחרי /#
אי אפשר לשים A* או a* נוסף אחרי שדה שהוצג ב־/ ב־unpack ולצפות שיתנהג - ה־* הוא חמדן:
# Wrong - $prio will be undef, $sm gets everything left
my ($src, $dst, $sm, $prio) = unpack "Z* Z* C A* C", $buf;
# Right - use /A* so $sm knows where to stop
my ($src, $dst, $sm, $prio) = unpack "Z* Z* C/A* C", $buf;
בתבנית השנייה, C/A* קורא מונה בתים ואז כך וכך בתים. כל מה שאחרי הקו הנטוי מכבד אותו, וה־C הגורר אוסף את הבית הבא כמצופה.
דוגמה מפותחת: זוגות מפתח־ערך#
פרוטוקול שומר מילון כ־count ולאחריו count זוגות של (length, key, length, value):
my %env = ( HOST => "example.com",
PORT => "443",
USER => "alice" );
my $blob = pack "S (S/A* S/A*)*",
scalar keys %env,
%env;
קריאתו בחזרה:
my %parsed = unpack "S/(S/A* S/A*)", $blob;
תבנית ה־pack אומרת: ״מונה 16-ביט אחד (של זוגות), ואז חזרו על תת־התבנית S/A* S/A* עבור כל זוג.״ תבנית ה־unpack קוראת את המונה ומחילה אותו על הקבוצה ישירות - המונה כבר לא נמצא ברשימת הפלט.
מקרי קצה ואילוצים#
ל־
/אין משמעות עם פריט באורך קבוע. ההוראה השנייה חייבת להיות ברוחב משתנה:a*,A*,Z*,/A$n, או דומה. Perl ידחה פריט שני באורך קבוע.()*עםpackאינו יכול להיות מותאם על־ידי()*ב־unpack. ל־pack יש את הערכים, אז הוא יכול לומר ״חזרו עד הסוף״. unpack אינו יודע כמה חזרות מקודדות במאגר אלא אם הוראת מונה מקדימה את הקבוצה.קבוצות מקוננות הן לגיטימיות ונפוצות:
pack "((CC)(S))<", @records
מתאמי endianness מתפזרים דרך כל רמת קינון.
מונה חזרות על קבוצה חל על הקבוצה כולה ולוקח כך וכך חזרות של ערכים.
(CS)3צורך שישה ערכי רשימה, לא שלושה.
פרק הבא: ההוראות הזזות בתוך תבנית מבלי לייצר ערך - x, X, @, ..