מחרוזות, ביטים וחצאי־בתים#

בסוף הפרק הזה תוכלו לארוז ולפענח מחרוזות ברוחב קבוע, מחרוזות מסוימות־NUL בסגנון C, מחרוזות ביטים ומחרוזות hex - שלוש משפחות ההוראות מעין־טקסטואליות.

פורמטים בינאריים נושאים נתוני מחרוזת במגוון טעמים מובחנים: בתים גולמיים, טקסט מרופד־רווחים, מחרוזות C מסוימות־NUL, שדות ביטים, מספרים מקודדי־hex. ל־pack יש הוראה לכל אחד.

שלוש הוראות המחרוזת: a / A / Z#

כל השלוש אורזות בדיוק ערך אחד לרוחב קבוע. הן נבדלות במה שהן מרפדות בו, ו - חשוב מאוד - במה ש־unpack מסיר חזרה:

אות

בית ריפוד

unpack מחזיר

שימוש טיפוסי

a

"\0" (NUL)

כל הבתים ללא שינוי

בינארי שרירותי

A

" " (רווח)

רווח גורר ו־NUL מוסרים

טקסט ASCII ברוחב קבוע

Z

"\0" (NUL)

בתים עד ל־NUL הראשון

מסוים־NUL בסגנון C

הרוחב הוא מונה החזרות, לא מונה ערכים:

pack "a4", "hi"           # "hi\0\0"
pack "A4", "hi"           # "hi  "
pack "Z4", "hi"           # "hi\0\0"

pack "a4", "abcdef"       # "abcd"  - truncated
pack "A*", "hello"        # "hello" - whatever the value's length is

Z מבטיח NUL גורר - עם הסתייגות#

Z תמיד שומר מקום ל־NUL מסיים אחד לפחות:

pack "Z*", "hello"        # "hello\0"   - a free NUL appended
pack "Z5", "hello"        # "hell\0"    - truncated to make room!

אם תוכנית C בצד השני מצפה ל־char[32] מסוים־אפס, השתמשו ב־Z32. הוא יארוז עד 31 בתים של נתונים בתוספת המסיים.

בחירה בין a ל־A לטקסט#

  • הנתונים הם ASCII, מרופדים ברווחים על הדיסק → A.

  • הנתונים הם בתים שרירותיים (עשויים להכיל רווחים או NULs כתוכן תקף) → a.

המלכודת הקלאסית: אתם אורזים שם עם A20 ופורמט החוט משתמש בריפוד NUL. unpack "A20" מסיר גם רווחים וגם NULs, אז זה נראה בסדר - אך pack "A20", "bob" יבצע נסיעה חזור ל־"bob " מרופד ברווחים. אם המפרט אומר ריפוד NUL, השתמשו ב־a בצד ה־pack.

דוגמה מפותחת: רשומות טקסט ברוחב קבוע#

קובץ פנקס מסדר נתונים בעמודות:

0         1         2         3         4
0123456789012345678901234567890123456789012345678
2026-04-22 coffee at the station           3.50
2026-04-23 train to Brussels              42.00

עמודה 1-10 היא התאריך, 12-38 התיאור, 40-47 הסכום. הפערים הם רווחים בודדים (בית 11 ובית 39). unpack עם A10 x A27 x A* מקלף כל רשומה:

while (<$ledger>) {
    chomp;
    my ($date, $desc, $amount) = unpack "A10 x A27 x A*", $_;
    print "  $date | $desc | $amount\n";
}

x מדלג על בית אחד; A27 אוכל את עמודת התיאור ומסיר רווחים גוררים; A* אוכל בחמדנות את הבתים הנותרים כסכום. צד הפלט משתמש בשדות רחבים יותר כדי שרווחים ישרדו את הנסיעה חזור:

my $line = pack "A11 A28 A8 A*", $date, $desc,
                                 sprintf("%.2f", $amt_left),
                                 sprintf("%12.2f", $amt_right);

שימו לב לבית הנוסף בכל רוחב A - אותו בית בודד נוסף הוא פער העמודה. תקציב בתים עקבי לכל עמודה הוא מה שהופך רשומות ברוחב קבוע לבנות־טיפול בכלל.

מחרוזות ביטים: b ו־B#

מחרוזת ביטים היא מחרוזת של תווי "0" ו־"1" הנארזת לביטים בפועל. שתי הוראות, הנבדלות רק בכיוון שבו קוראים כל בית:

הוראה

סדר ביטים בתוך כל בית

b

LSB ראשון - ביט 0, 1, 2, 3, 4, 5, 6, 7

B

MSB ראשון - ביט 7, 6, 5, 4, 3, 2, 1, 0

מונה החזרות הוא מספר הביטים, לא בתים:

pack "B8", "10001100"      # "\x8c" - MSB first, bit 7 set, bit 3 & 2 set
pack "b8", "00110001"      # "\x8c" - LSB first, same byte

B מתאים למוסכמה הרגילה ״משמאל־לימין הוא מגבוה־לנמוך״ שרואים ב־dumps בינאריים; b מתאים למוסכמה המשמשת חלק מ־hardware registers ול־built-in vec. השתמשו ב־B כאשר אתם כותבים החוצה מספר בינארי ״רגיל״, ב־b כאשר אתם משקפים data sheet שממספר את ביט 0 בצד ימין.

ספירת ביטים דלוקים#

אחד השימושים המפתיעים יותר של unpack: ספירת ביטים דלוקים במאגר בקריאה אחת. %32b* מפענח את הביטים ומבקש סכום 32-ביט, שהוא המונה:

my $n_bits = unpack "%32b*", $mask;

הקידומת %N היא ל־unpack בלבד - ראו את פרק המיקום לשימושים האחרים.

מחרוזות hex: h ו־H#

מחרוזות hex הן ייצוג הטקסט שרוב המפתחים קוראים - שתי ספרות hex לכל בית. שתי הוראות, הנבדלות בסדר החצאי־בתים:

הוראה

סדר חצאי־בתים

h

חצי־בית נמוך ראשון

H

חצי־בית גבוה ראשון

H הוא ה־hex dump ה״רגיל״ - קריאה משמאל לימין, ספרה גבוהה ואז נמוכה:

pack "H*", "deadbeef"      # "\xde\xad\xbe\xef"
unpack "H*", "\xde\xad\xbe\xef"   # "deadbeef"

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

pack "h*", "ef"            # "\xfe"  (nybbles swapped)
pack "H*", "ef"            # "\xef"

בחירה ביניהם#

יש לכם

פנו אל

ASCII בעמודה ברוחב קבוע על הדיסק

A

בתים שרירותיים בחריץ ברוחב קבוע

a

מחרוזת מסוימת־NUL בסגנון C

Z

מספר בינארי כמחרוזת של 0 / 1

B

זהה, עם סדר הביטים של מוסכמת register

b

מחרוזת hex בסדר הקריאה הרגיל

H

מחרוזת hex עם חצאי־בתים מוחלפים

h

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

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