רשימות · נתונים באורך קבוע

unpack#

חילוץ ערכים בעלי טיפוס ממחרוזת בינארית או באורך קבוע לפי תבנית.

unpack הוא ההפך של pack. הוא הולך לאורך EXPR משמאל לימין, צורך את הבתים המתוארים על־ידי כל הוראה ב־TEMPLATE והופך אותם לערכי Perl. התוצאה היא רשימה - ערך אחד לכל הוראה, או לכל חזרה כאשר להוראה יש מונה. אם EXPR מושמט, unpack קורא מ־$_.

עמוד זה הוא מדריך עיון להוראות. למבוא נרטיבי עם דוגמאות פרוטוקול ופורמט קובץ מעובדות, יש להתחיל ב־הדרכת pack/unpack.

תקציר#

unpack TEMPLATE, EXPR
unpack TEMPLATE                             # reads from $_
my @fields = unpack "A10 A10 A*", $line;
my ($ver, $len, $payload) = unpack "n N A*", $msg;

מה מוחזר#

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

my @all   = unpack "A4 A4 A*", $rec;    # three values
my $first = unpack "A4 A4 A*", $rec;    # just the first - not a count

כל הוראה קובעת את טיפוס ה־Perl של התוצאה שלה - ראו את העמודה ״טיפוס תוצאה״ בטבלת ההוראות להלן.

מצב גלובלי שהוא נוגע בו#

unpack TEMPLATE ללא EXPR קורא מ־$_. אף משתנה גלובלי אחר של המפרש אינו נצרך. ההוראות C0 / U0 מחליפות פירוש בית־מול־תו של התבנית מקומית בתוך התבנית אך אינן משנות שום מצב חיצוני.

תחביר תבנית#

זהה ל־pack: רצף של אותיות הוראה, ואחריהן אופציונלית מוני חזרות N / * / […] ומתאמים ! / < / >. סוגריים יוצרים קבוצות; # מציג הערת תבנית. ראו pack לכללי התחביר המלאים - עמוד זה מכסה רק את הסמנטיקה הייחודית ל־unpack.

טבלת הוראות#

כל הוראת unpack במקום אחד. W הוא הרוחב בבתים הנצרך מהקלט לכל סקלר שמופק.

הוראה

W

עם סימן

Endian

טיפוס תוצאה

מתאמים

הערות

a

מונה

-

-

מחרוזת

-

מחזיר בתים ללא שינוי

A

מונה

-

-

מחרוזת

-

מסיר רווח לבן ו־NUL מסיימים

Z

מונה

-

-

מחרוזת

-

מחזיר את כל מה שעד ה־NUL הראשון

b

מונה/8

-

-

מחרוזת ביטים

-

תווי ”0“/“1“, LSB של כל בית ראשון

B

מונה/8

-

-

מחרוזת ביטים

-

תווי ”0“/“1“, MSB של כל בית ראשון

h

מונה/2

-

-

מחרוזת הקסה

-

תווי [0-9a-f], חצי־בית נמוך ראשון

H

מונה/2

-

-

מחרוזת הקסה

-

תווי [0-9a-f], חצי־בית גבוה ראשון

c

1

כן

-

מספר שלם

-

char עם סימן

C

1

לא

-

מספר שלם

-

char ללא סימן

W

1

לא

-

מספר שלם

-

char ללא סימן; מניב נקודת קוד במצב U0

s

2

כן

native

מספר שלם

! < >

s! = short native

S

2

לא

native

מספר שלם

! < >

S! = unsigned short native

l

4

כן

native

מספר שלם

! < >

l! = long native

L

4

לא

native

מספר שלם

! < >

L! = unsigned long native

i

native

כן

native

מספר שלם

! < >

sizeof(int)

I

native

לא

native

מספר שלם

! < >

sizeof(unsigned int)

q

8

כן

native

מספר שלם

< >

דורש Perl עם מספרים שלמים 64־ביט

Q

8

לא

native

מספר שלם

< >

דורש Perl עם מספרים שלמים 64־ביט

n

2

לא

big

מספר שלם

!

סדר רשת; n! = עם סימן

N

4

לא

big

מספר שלם

!

סדר רשת; N! = עם סימן

v

2

לא

little

מספר שלם

!

סדר ״VAX״; v! = עם סימן

V

4

לא

little

מספר שלם

!

סדר ״VAX״; V! = עם סימן

j

גודל IV

כן

native

מספר שלם

< >

IV פנים־Perl

J

גודל UV

לא

native

מספר שלם

< >

UV פנים־Perl

f

4

-

native

מספר

< >

דיוק יחיד IEEE 754

d

8

-

native

מספר

< >

דיוק כפול IEEE 754

F

גודל NV

-

native

מספר

< >

מספר נקודה צפה פנים־Perl

D

משתנה

-

native

מספר

< >

double ארוך

p

גודל ptr

-

native

מחרוזת

< >

מבצע dereference למצביע למחרוזת המסתיימת ב־NUL

P

גודל ptr

-

native

מחרוזת

< >

מבצע dereference למצביע; מונה = בתים לקריאה

u

משתנה

-

-

מחרוזת

-

בתים מפוענחי uudecode

U

משתנה

-

-

מספר שלם

-

מספר נקודת קוד של Unicode

w

משתנה

לא

-

מספר שלם

-

מספר שלם דחוס־BER

x

1

-

-

(אין)

!

דילוג בית אחד קדימה; x!N מיישר קדימה

X

−1

-

-

(אין)

!

חזרה בית אחד אחורה; X!N מיישר לאחור

@

מוחלט

-

-

(אין)

!

קפיצה למיקום N בתוך הקבוצה הפנימית ביותר

.

-

-

-

מספר שלם

!

החזרת המיקום הנוכחי (יחסית להתחלת הקבוצה / המחרוזת)

( )

-

-

-

-

< > !

קבוצה: מונה חזרות ו־endianness מתפשטים פנימה

/

-

-

-

-

-

ראו ״מטענים בעלי קידומת אורך״ להלן

%N

משתנה

-

-

מספר שלם

-

קידומת. checksum בן N־ביט של ערכי ההוראה הבאה

למתאמים אותה משמעות כמו ב־pack: ! בוחר גדלים native, סמנטיקת יישור, סימן עבור n / N / v / V, או היסטי בתים עבור @ / .; < / > כופים endianness.

הבדלים מ־pack#

  • a אינו מסיר דבר (מחזיר בתים גולמיים); A מסיר רווח לבן ו־NUL מסיימים; Z עוצר ב־NUL הראשון. ב־pack כל השלוש מרפדות; ב־unpack כל השלוש מסירות־ריפוד באופן שונה.

  • x מדלג קדימה ב־W, X חוזר אחורה ב־W. X לפני תחילת המחרוזת היא שגיאה קטלנית.

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

    unpack("W/a", "\004Gurusamy")          # ("Guru")
    unpack("a3/A A*", "007 Bond  J ")      # (" Bond", "J")
    unpack("n/a*", "\x00\x0chello, world") # ("hello, world")
    

    ב־pack הצורה היא length-item/item והאורך מחושב מאורך הערך. ב־unpack הצורה היא /item (ללא length-item לפני) - הוראת המספר השלם הקודמת מספקת את המונה.

  • %N הוא לשימוש unpack בלבד. הוא מחליף את הפלט הרגיל של ההוראה הבאה בסכום בן N־ביט של הערכים שההוראה הייתה מפיקה אחרת. %32W* הוא checksum של sum ב־System V. %32b* סופר ביטים מודלקים.

  • . מחזיר את מיקום הבית הנוכחי במקום למלא באפסים עד אליו. שימושי לאחר ניווט x / X כדי לדעת היכן נמצאים.

  • p ו־P מבצעים dereference למצביעים שנקראו מהקלט - כמעט תמיד לא־בטוח אלא אם יודעים שהקלט הופק על־ידי pack "p" / pack "P" באותו תהליך.

  • התנהגות under-run / over-run: אם התבנית מבקשת יותר נתונים ממה ש־EXPR מכיל, התוצאה אינה מוגדרת היטב (עלולה להניב מחרוזות ריקות, אפסים, מונה חזרות מופחת, או חריגה). אם EXPR ארוך יותר ממה שהתבנית צורכת, בתים מסיימים נדחים בשקט.

דוגמאות#

פרסור של כותר פרוטוקול בינארי מינימלי - גרסה 16־ביט, אורך 32־ביט, ואז מטען באורך משתנה, הכול בסדר בתי רשת:

my ($ver, $len, $payload) = unpack "n N A*", $msg;

פיצול רשומת טקסט ברוחב קבוע - מהיר וברור יותר מקריאות substr משורשרות:

my ($date, $desc, $amount) = unpack "A10 A27 A*", $line;
# "2026-04-22 coffee at the station           3.50"
# $date = "2026-04-22", $desc = "coffee at the station",
# $amount = "3.50"

חילוץ checksum בסגנון System V עם הקידומת % - הסכום 32־ביט של כל בית, ממוסך ל־16 ביטים:

my $checksum = do {
    local $/;                           # slurp
    unpack "%32W*", readline $fh;
} % 65535;

ספירת ביטים מודלקים בווקטור ביטים - %32b* קורא את כל המסכה כביטים ומחזיר את הסכום שלהם:

my $setbits = unpack "%32b*", $selectmask;

קריאת רצף של מספרים שלמים 32־ביט little-endian מבופר גולמי:

my @ints = unpack "V*", $buf;

שימוש ב־x לדילוג על בתי מילוי, X לחזרה אחורה לאחר הצצה:

# 2-byte tag, skip 2 reserved bytes, then 4 32-bit big-endian values
my ($tag, @vals) = unpack "n x2 N4", $frame;

מקרי קצה#

  • הקשר סקלרי מחזיר רק את הערך הראשון. השמת unpack לסקלר היא כמעט אף פעם לא מה שרוצים. כדי לספור שדות, יש להשים לרשימה ראשון, או להשתמש ב־() = unpack ... בהקשר רשימה:

    my $n = () = unpack "A10 A10 A*", $line;   # 3
    
  • * חמדן, לא מציין־מקום. A* צורך את כל הבתים הנותרים כמחרוזת אחת; אין חזרה לאחור. הוראת * חייבת להיות האחרונה ברצף שלה, אחרת דבר אחריה אינו רץ.

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

  • סמנטיקת בית מול תו. unpack רץ במצב בתים כברירת מחדל על מחרוזת בתים, ובמצב תווים על מחרוזת עם דגל UTF-8 מודלק. C0 כופה מצב בתים מהנקודה ההיא; U0 כופה מצב UTF-8. ערבוב מחרוזת מסומנת־UTF-8 עם הוראות מספריות כגון N קורא נקודות קוד, לא בתים - בדרך כלל לא מה שרוצים. יש לקרוא ל־utf8::encode ראשון, או לפעול על נתונים ברמת בית.

  • X שמעבר לתחילת המחרוזת הוא קטלני.

  • p / P על קלט שרירותי הוא התנהגות לא מוגדרת. אין להשתמש בהם אף פעם על נתונים שלא ארזתם בעצמכם באותו תהליך.

  • ללא ארגומנט EXPR: unpack TEMPLATE קורא מ־$_. שימושי בתוך לולאות while (<$fh>) { ... } על רשומות ברוחב קבוע.

הבדלים מהמעלה־הזרם#

תאימות מלאה עם Perl 5.42 מהמעלה־הזרם.

ראו גם#

  • pack - הפעולה ההפוכה; אותה שפת תבניות

  • substr - חילוץ פרוסה קבועה יחידה; פשוט יותר עבור שדה אחד, איטי יותר עבור רבים

  • sprintf - מסלול הלוך־ושוב בין בינארי לקריא־לאדם

  • read - קריאת בתים גולמיים ממטפל קובץ לבופר עבור unpack

  • vec - גישה מאונדקסת לווקטור ביטים ללא תבנית

  • הדרכת pack/unpack - סיור מבוסס־משימות עם דוגמאות פרוטוקול ופורמט קובץ מעובדות