סקלרים ומחרוזות · נתונים באורך קבוע
pack#
המרת רשימת ערכי Perl למחרוזת בינארית לפי תבנית.
pack הוא הסריאלייזר ברמה הנמוכה: מתארים את פריסת הבתים עם TEMPLATE, מוסרים לו LIST של ערכים, והוא מחזיר סקלר שתוויו הם הקידוד המשורשר ברמת המכונה של אותם ערכים. הוא ההפך של unpack והדרך הסטנדרטית לבנות רשומות באורך קבוע, פרוטוקולי חוט, פריסות struct של C, כתובות IP גולמיות עבור sockaddr_in, וכל מטען ברמת־בתים אחר ש־Perl אינו ממדל כטיפוס מהמעלה הראשונה.
This page is a directive reference. For a narrative introduction
”I have this wire protocol, how do I parse it?“ - start at the pack/unpack tutorial.
תקציר#
my $bytes = pack TEMPLATE, LIST;
my $ip = pack "C4", split /\./, "192.168.1.1";
my $rec = pack "Z8 Z8 L", $user, $host, $ts;
מה מוחזר#
סקלר Perl פשוט המחזיק את הבתים הארוזים. אורכו הוא סכום הרוחבים של כל הוראת תבנית; תוכנו בינארי ועלול להכיל בתי NUL מוטמעים. יש להתייחס אליו כמחרוזת בתים, לא כטקסט - כתיבתו למטפל עם שכבה :utf8 או :encoding(…) תקודד אותו מחדש. יש להשתמש ב־binmode $fh או לפתוח עם ">:raw" לפני הפליטה.
כברירת מחדל התוצאה היא במצב תווים (C0). תבנית המתחילה ב־U, או עוברת ל־U0 באמצע התבנית, מפיקה במקום זאת מחרוזת Unicode מקודדת UTF-8. אין להשתמש בכך כתחליף למודול Encode.
תחביר תבנית#
TEMPLATE היא רצף של הוראות. כל הוראה היא אות ASCII, ואחריה אופציונלית:
מונה חזרות - מספר שלם עשרוני,
*, או[…]מתאם אחד או יותר -
!,<,>קבוצה -
( … )אוספת הוראות כך שמונה חזרות או מתאם endianness חל על כולה
רווח לבן בין הוראות נדחה. # מציג הערה הנמשכת לסוף השורה - אותה מוסכמה כמו במקור Perl.
טבלת הוראות#
כל הוראת pack במקום אחד. W הוא הרוחב בבתים לכל סקלר נצרך (C צורך ערך אחד ומפיק בית אחד; a3 צורך ערך אחד ומפיק שלושה בתים). עמודת Endian: native פירושו סדר הבתים של המעבד; big / little קבועים ללא קשר למארח.
הוראה | צורך | W | עם סימן | Endian | מתאמים | הערות |
|---|---|---|---|---|---|---|
| מחרוזת אחת | מונה | - | - | - | מרופד ב־NUL לרוחב, נחתך אם ארוך מדי |
| מחרוזת אחת | מונה | - | - | - | מרופד ברווחים לרוחב |
| מחרוזת אחת | מונה | - | - | - | מסתיים ב־NUL; |
| מחרוזת אחת | מונה/8 | - | - | - | מחרוזת ביטים, LSB ראשון בתוך כל בית |
| מחרוזת אחת | מונה/8 | - | - | - | מחרוזת ביטים, MSB ראשון בתוך כל בית |
| מחרוזת אחת | מונה/2 | - | - | - | מחרוזת הקסה, חצי־בית נמוך ראשון |
| מחרוזת אחת | מונה/2 | - | - | - | מחרוזת הקסה, חצי־בית גבוה ראשון |
| מספר שלם אחד | 1 | כן | - | - | char עם סימן |
| מספר שלם אחד | 1 | לא | - | - | char ללא סימן (אוקטט) |
| מספר שלם אחד | 1 | לא | - | - | char ללא סימן; מאפשר ערכים מעל 255 במצב |
| מספר שלם אחד | 2 | כן | native |
|
|
| מספר שלם אחד | 2 | לא | native |
|
|
| מספר שלם אחד | 4 | כן | native |
|
|
| מספר שלם אחד | 4 | לא | native |
|
|
| מספר שלם אחד | native | כן | native |
|
|
| מספר שלם אחד | native | לא | native |
|
|
| מספר שלם אחד | 8 | כן | native |
| דורש Perl עם מספרים שלמים 64־ביט |
| מספר שלם אחד | 8 | לא | native |
| דורש Perl עם מספרים שלמים 64־ביט |
| מספר שלם אחד | 2 | לא | big |
| סדר רשת נייד; |
| מספר שלם אחד | 4 | לא | big |
| סדר רשת נייד; |
| מספר שלם אחד | 2 | לא | little |
| סדר ״VAX״; |
| מספר שלם אחד | 4 | לא | little |
| סדר ״VAX״; |
| מספר שלם אחד | גודל IV | כן | native |
| מספר שלם עם סימן פנים־Perl |
| מספר שלם אחד | גודל UV | לא | native |
| מספר שלם ללא סימן פנים־Perl |
| מספר אחד | 4 | - | native |
| דיוק יחיד IEEE 754 |
| מספר אחד | 8 | - | native |
| דיוק כפול IEEE 754 |
| מספר אחד | גודל NV | - | native |
| מספר נקודה צפה פנים־Perl ( |
| מספר אחד | משתנה | - | native |
| double ארוך; הפורמט משתנה לפי פלטפורמה |
| מחרוזת אחת / | ptr | - | native |
| מצביע למחרוזת המסתיימת ב־NUL; |
| מחרוזת אחת / | ptr | - | native |
| מצביע לבופר באורך קבוע; מונה = אורך הבופר |
| מחרוזת אחת | משתנה | - | - | - | מקודד uuencode; מונה = מקסימום בתים לשורת פלט (ברירת מחדל 45) |
| נקודת קוד אחת | משתנה | - | - | - | מספר תו Unicode; מקודד ל־UTF-8 במצב |
| מספר שלם אחד ≥ 0 | משתנה | לא | - | - | מספר שלם דחוס־BER, big-endian בבסיס 128 |
| כלום | 1 | - | - |
| הוספת |
| כלום | −1 | - | - |
| חזרה בית אחד אחורה; |
| כלום | מוחלט | - | - |
| מילוי באפסים או חיתוך למיקום N בתוך הקבוצה |
| מספר שלם אחד | מוחלט | - | - |
| מילוי באפסים או חיתוך למיקום הנתון על־ידי הערך |
| - | - | - | - |
| קבוצה: מונה חזרות ו־endianness מתפשטים פנימה |
| - | - | - | - | - | unpack בלבד. ב־pack, יש להשתמש ב־length-item |
המתאמים:
מתאם | אפקט |
|---|---|
| על |
| לאלץ סדר בתים big-endian (״הקצה הגדול נוגע במבנה״). |
| לאלץ סדר בתים little-endian. |
בהחלה על קבוצה, < / > מתפשטים אל כל הוראה תלוית סדר־בתים בתוך הקבוצה ודוחים בשקט על־ידי הוראות שאינן מקבלות אותם.
מוני חזרות#
אות הוראה יכולה להיות מלווה ב:
מספר
N- החלת ההוראה כך וכך פעמים, צריכתNערכים מ־LIST*- צריכת כל הערכים הנותרים; עבורx/X/@זה שקול ל־0; עבורuזה בוחר את ברירת המחדל של 45[N]- שקול ל־Nחשוף[template]- מונה החזרות הוא אורך הבתים הארוז של template.x[L]מדלג על כמות הבתים של long ארוז;x![d]מיישר לגבול של double
הוראות מחרוזת וביט/חצי־בית מתייחסות למונה כרוחב של ערך יחיד, לא כמונה־ערכים: pack "A4", "abcdef" מפיק "abcd", לא ארבעה עותקים של "abcdef".
קיבוץ#
סוגריים מקבצים הוראות. קבוצה יכולה לקבל מונה חזרות או מתאם endianness:
pack "(sl)<", -42, 4711 # same as "s<l<", -42, 4711
pack "(CCS)*", @triplets # repeat group for every triplet
Within each repetition of a group, @ positioning starts over at 0
pack '@1A((@2A)@3A)', qw(X Y Z)produces"\0X\0\0YZ".
מטענים בעלי קידומת אורך (/)#
יש לכתוב length-item/sequence-item. האורך מחושב מערך הרצף ונארז לפי length-item; ואז הרצף עצמו נארז לפי sequence-item:
my $msg = pack "n/a*", "hello, world";
# "\x00\x0chello, world" - 16-bit big-endian length, then the bytes
הוראת האורך יכולה להיות כל הוראת מספר שלם (n, N, w, C, …) או אפילו הוראת מחרוזת (A4, Z*) כאשר רוצים שהאורך ייכתב כ־ASCII.
דוגמאות#
בניית רשומה ברוחב קבוע עם שתי מחרוזות המסתיימות ב־NUL וחותמת זמן native 32־ביט:
my $rec = pack "Z8 Z8 L", "alice", "server01", $now;
# 8 + 8 + 4 = 20 bytes
סדר בתי רשת נייד - עדיף n / N / v / V על־פני הוראות ברוחב native כאשר הבתים עוזבים את המכונה:
my $be = pack "n N", 42, 4711; # big-endian 16 + 32 bit
my $le = pack "v V", 42, 4711; # little-endian
my $sx = pack "s>l>", -42, 4711; # signed big-endian via modifier
my $gx = pack "(sl)<", -42, 4711; # signed little-endian via group
יישור שדה בתוך struct של C. x![d] מכניס בדיוק את כמות בתי ה־NUL הדרושה כדי להגיע לכפולה הבאה של רוחב double:
# struct { char c; double d; char cc[2]; }
my $s = pack "c x![d] d c2", $c, $d, $c1, $c2;
מסלול הלוך־ושוב דרך מחרוזת הקסה:
my $raw = pack "H*", "deadbeef"; # "\xde\xad\xbe\xef"
my $hex = unpack "H*", $raw; # "deadbeef"
מקרי קצה#
מעט מדי ערכים: ערכים חסרים מטופלים כ־
"".pack "A4 A4", "hi"מניב"hi \0\0\0\0", לא שגיאה קטלנית.יותר מדי ערכים: עודפים נדחים בשקט.
aמולAמולZ: כל השלוש מרפדות לרוחב מדויק.aמרפד ב־NUL,Aמרפד ברווח,Zמרפד ב־NULומבטיחNULמסיים - כך ש־Z8מקודד לכל היותר 7 בתי נתונים בתוספת המסיים.רוחב תווים מול רוחב בתים - המלכודת הנפוצה ביותר. מונים עבור
a/A/Zוהיסטים עבור@/.הם בתווים של המחרוזת הארוזה, לא בתים. במצבC0תו הוא בית אחד; במצבU0תו עשוי להשתרע על מספר בתי UTF-8. יש להשתמש במתאם!על@/.כאשר נדרשים היסטי בתים ללא קשר למצב.Endianness על
s/S/l/L/i/I/q/Q: native בלבד, לא נייד. יש להשתמש ב־n/N/v/Vאו להחיל>/<במפורש.f/dגם כן native; IEEE 754 לבדו אינו מקבע endianness.Inf/NaNהארוזים כמספרים שלמים: שגיאה קטלנית. אין מיפוי הגיוני.q/Qעל Perl שאינו 64־ביט: זורק חריגה.pו־Pלוכדים מצביעים לתוך הזיכרון של הקורא. המוצבע חייב להישאר חי עד שהמחרוזת הארוזה נצרכת - מחרוזת זמנית המועברת ל־pעלולה להשתחרר לפני שתקראו אותה בחזרה. יש להימנע מחוץ לקוד XS.קיבוץ ו־
@: מיקום עם@מתחיל מחדש מ־0 בתוך כל חזרה של קבוצה.pack '@1A((@2A)@3A)', qw(X Y Z)מפיק"\0X\0\0YZ", לא את מה שקריאה תמימה מציעה.אובדן בהלוך־ושוב של נקודה צפה: Perl מאחסן מספרים כ־double, כך ש־
unpack("f", pack("f", $x))בדרך כלל אינו שווה ל־$x- אריזה דרך דיוק יחיד חותכת.כתיבת בתים ארוזים למטפל טקסט: מטפל עם
:utf8או:encoding(…)יקודד מחדש את הבתים. יש להשתמש ב־binmode $fhאו לפתוח עם">:raw".
הבדלים מהמעלה־הזרם#
תאימות מלאה עם Perl 5.42 מהמעלה־הזרם.