Spec-Zone.ru › Ruby 3.4

Упакованные данные

Краткий справочник

В этих таблицах суммируются директивы для упаковки и распаковки.

Для целых чисел

Directive     | Meaning
--------------|---------------------------------------------------------------
C             | 8-bit unsigned (unsigned char)
S             | 16-bit unsigned, native endian (uint16_t)
L             | 32-bit unsigned, native endian (uint32_t)
Q             | 64-bit unsigned, native endian (uint64_t)
J             | pointer width unsigned, native endian (uintptr_t)

c             | 8-bit signed (signed char)
s             | 16-bit signed, native endian (int16_t)
l             | 32-bit signed, native endian (int32_t)
q             | 64-bit signed, native endian (int64_t)
j             | pointer width signed, native endian (intptr_t)

S_ S!         | unsigned short, native endian
I I_ I!       | unsigned int, native endian
L_ L!         | unsigned long, native endian
Q_ Q!         | unsigned long long, native endian
              |   (raises ArgumentError if the platform has no long long type)
J!            | uintptr_t, native endian (same with J)

s_ s!         | signed short, native endian
i i_ i!       | signed int, native endian
l_ l!         | signed long, native endian
q_ q!         | signed long long, native endian
              |   (raises ArgumentError if the platform has no long long type)
j!            | intptr_t, native endian (same with j)

S> s> S!> s!> | each the same as the directive without >, but big endian
L> l> L!> l!> |   S> is the same as n
I!> i!>       |   L> is the same as N
Q> q> Q!> q!> |
J> j> J!> j!> |

S< s< S!< s!< | each the same as the directive without <, but little endian
L< l< L!< l!< |   S< is the same as v
I!< i!<       |   L< is the same as V
Q< q< Q!< q!< |
J< j< J!< j!< |

n             | 16-bit unsigned, network (big-endian) byte order
N             | 32-bit unsigned, network (big-endian) byte order
v             | 16-bit unsigned, VAX (little-endian) byte order
V             | 32-bit unsigned, VAX (little-endian) byte order

U             | UTF-8 character
w             | BER-compressed integer

Для чисел с плавающей точкой

Directive | Meaning
----------|--------------------------------------------------
D d       | double-precision, native format
F f       | single-precision, native format
E         | double-precision, little-endian byte order
e         | single-precision, little-endian byte order
G         | double-precision, network (big-endian) byte order
g         | single-precision, network (big-endian) byte order

Для строк

Directive | Meaning
----------|-----------------------------------------------------------------
A         | arbitrary binary string (remove trailing nulls and ASCII spaces)
a         | arbitrary binary string
Z         | null-terminated string
B         | bit string (MSB first)
b         | bit string (LSB first)
H         | hex string (high nibble first)
h         | hex string (low nibble first)
u         | UU-encoded string
M         | quoted-printable, MIME encoding (see RFC2045)
m         | base64 encoded string (RFC 2045) (default)
          |   (base64 encoded string (RFC 4648) if followed by 0)
P         | pointer to a structure (fixed-length string)
p         | pointer to a null-terminated string

Дополнительные директивы для упаковки

Directive | Meaning
----------|----------------------------------------------------------------
@         | moves to absolute position
X         | back up a byte
x         | null byte

Дополнительные директивы для распаковки

Directive | Meaning
----------|----------------------------------------------------------------
@         | skip to the offset given by the length argument
X         | skip backward one byte
x         | skip forward one byte

Упаковка и распаковки

Определенные методы ядра Ruby обрабатывают упаковку и распаковку данных:

  • Метод Array#pack: Форматирует каждый элемент в массиве self в двоичную строку; возвращает эту строку.

  • Метод String#unpack: Извлекает данные из строки self, формируя объекты, которые становятся элементами нового массива; возвращает этот массив.

  • Метод String#unpack1: Делает то же самое, но распаковывает и возвращает только первый извлеченный объект.

Каждый из этих методов принимает строку template, состоящую из нуля или более символов директивы, каждый из которых следует за нулем или более символами модификатора.

Примеры (директива 'C' указывает «беззнаковый символ»):

[65].pack('C')      # => "A"  # One element, one directive.
[65, 66].pack('CC') # => "AB" # Two elements, two directives.
[65, 66].pack('C')  # => "A"  # Extra element is ignored.
[65].pack('')       # => ""   # No directives.
[65].pack('CC')               # Extra directive raises ArgumentError.

'A'.unpack('C')   # => [65]      # One character, one directive.
'AB'.unpack('CC') # => [65, 66]  # Two characters, two directives.
'AB'.unpack('C')  # => [65]      # Extra character is ignored.
'A'.unpack('CC')  # => [65, nil] # Extra directive generates nil.
'AB'.unpack('')   # => []        # No directives.

Строка template может содержать любую комбинацию допустимых директив (директива 'c' указывает «знаковый символ»):

[65, -1].pack('cC')  # => "A\xFF"
"A\xFF".unpack('cC') # => [65, 255]

Строка template может содержать пробелы (которые игнорируются) и комментарии, каждый из которых начинается с символа '#' и продолжается до и включая следующую строку:

[0,1].pack("  C  #foo \n  C  ")    # => "\x00\x01"
"\0\1".unpack("  C  #foo \n  C  ") # => [0, 1]

Любая директива может быть дополнена одним из следующих модификаторов:

  • '*' - Директива применяется столько раз, сколько нужно:

    [65, 66].pack('C*') # => "AB"
    'AB'.unpack('C*')   # => [65, 66]
    
  • Integer count - Директива применяется count раз:

    [65, 66].pack('C2') # => "AB"
    [65, 66].pack('C3') # Raises ArgumentError.
    'AB'.unpack('C2')   # => [65, 66]
    'AB'.unpack('C3')   # => [65, 66, nil]
    

    Примечание: Директивы в %w[A a Z m] используют count по-разному; см. Директивы строк.

Если элементы не соответствуют предоставленной директиве, кодируются только младшие биты:

[257].pack("C").unpack("C") # => [1]

Метод упаковки

Метод Array#pack принимает необязательный ключевой аргумент buffer, который задаёт целевую строку (вместо новой строки):

[65, 66].pack('C*', buffer: 'foo') # => "fooAB"

Метод может принимать блок:

# Packed string is passed to the block.
[65, 66].pack('C*') {|s| p s }    # => "AB"

Методы распаковки

Методы String#unpack и String#unpack1 каждый принимает необязательный ключевой аргумент offset, который задаёт смещение в строке:

'ABC'.unpack('C*', offset: 1)  # => [66, 67]
'ABC'.unpack1('C*', offset: 1) # => 66

Оба метода могут принимать блок:

# Each unpacked object is passed to the block.
ret = []
"ABCD".unpack("C*") {|c| ret << c }
ret # => [65, 66, 67, 68]

# The single unpacked object is passed to the block.
'AB'.unpack1('C*') {|ele| p ele } # => 65

Директивы целых чисел

Каждая директива целого числа задаёт упаковку или распаковку одного элемента в входном или выходном массиве.

8-битные директивы целых чисел

  • 'c' - 8-битное знаковое целое число (как C signed char):

    [0, 1, 255].pack('c*')  # => "\x00\x01\xFF"
    s = [0, 1, -1].pack('c*') # => "\x00\x01\xFF"
    s.unpack('c*') # => [0, 1, -1]
    
  • 'C' - 8-битное беззнаковое целое число (как C unsigned char):

    [0, 1, 255].pack('C*')    # => "\x00\x01\xFF"
    s = [0, 1, -1].pack('C*') # => "\x00\x01\xFF"
    s.unpack('C*')            # => [0, 1, 255]
    

16-битные целые числовые директивы

  • 's' - 16-битное знаковое целое число, родной порядок байтов (как в C int16_t):

    [513, -514].pack('s*')      # => "\x01\x02\xFE\xFD"
    s = [513, 65022].pack('s*') # => "\x01\x02\xFE\xFD"
    s.unpack('s*')              # => [513, -514]
    
  • 'S' - 16-битное беззнаковое целое число, родной порядок байтов (как в C uint16_t):

    [513, -514].pack('S*')      # => "\x01\x02\xFE\xFD"
    s = [513, 65022].pack('S*') # => "\x01\x02\xFE\xFD"
    s.unpack('S*')              # => [513, 65022]
    
  • 'n' - 16-битное целое число в сетевом порядке, порядок байтов big-endian:

    s = [0, 1, -1, 32767, -32768, 65535].pack('n*')
    # => "\x00\x00\x00\x01\xFF\xFF\x7F\xFF\x80\x00\xFF\xFF"
    s.unpack('n*')
    # => [0, 1, 65535, 32767, 32768, 65535]
    
  • 'v' - 16-битное целое число VAX, порядок байтов little-endian:

    s = [0, 1, -1, 32767, -32768, 65535].pack('v*')
    # => "\x00\x00\x01\x00\xFF\xFF\xFF\x7F\x00\x80\xFF\xFF"
    s.unpack('v*')
    # => [0, 1, 65535, 32767, 32768, 65535]
    

32-битные целые числовые директивы

  • 'l' - 32-битное знаковое целое число, родной порядок байтов (как в C int32_t):

    s = [67305985, -50462977].pack('l*')
    # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC"
    s.unpack('l*')
    # => [67305985, -50462977]
    
  • 'L' - 32-битное беззнаковое целое число, родной порядок байтов (как в C uint32_t):

    s = [67305985, 4244504319].pack('L*')
    # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC"
    s.unpack('L*')
    # => [67305985, 4244504319]
    
  • 'N' - 32-битное целое число в сетевом порядке, порядок байтов big-endian:

    s = [0,1,-1].pack('N*')
    # => "\x00\x00\x00\x00\x00\x00\x00\x01\xFF\xFF\xFF\xFF"
    s.unpack('N*')
    # => [0, 1, 4294967295]
    
  • 'V' - 32-битное целое число VAX, порядок байтов little-endian:

    s = [0,1,-1].pack('V*')
    # => "\x00\x00\x00\x00\x01\x00\x00\x00\xFF\xFF\xFF\xFF"
    s.unpack('v*')
    # => [0, 0, 1, 0, 65535, 65535]
    

64-битные целые числовые директивы

  • 'q' - 64-битное знаковое целое число, родной порядок байтов (как в C int64_t):

    s = [578437695752307201, -506097522914230529].pack('q*')
    # => "\x01\x02\x03\x04\x05\x06\a\b\xFF\xFE\xFD\xFC\xFB\xFA\xF9\xF8"
    s.unpack('q*')
    # => [578437695752307201, -506097522914230529]
    
  • 'Q' - 64-битное беззнаковое целое число, родной порядок байтов (как в C uint64_t):

    s = [578437695752307201, 17940646550795321087].pack('Q*')
    # => "\x01\x02\x03\x04\x05\x06\a\b\xFF\xFE\xFD\xFC\xFB\xFA\xF9\xF8"
    s.unpack('Q*')
    # => [578437695752307201, 17940646550795321087]
    

Директивы целочисленных типов, зависящие от платформы

  • 'i' - знаковое целое число с шириной, зависящей от платформы, родной порядок байтов (как в C int):

    s = [67305985, -50462977].pack('i*')
    # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC"
    s.unpack('i*')
    # => [67305985, -50462977]
    
  • 'I' - беззнаковое целое число с шириной, зависящей от платформы, родной порядок байтов (как в C unsigned int):

    s = [67305985, -50462977].pack('I*')
    # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC"
    s.unpack('I*')
    # => [67305985, 4244504319]
    
  • 'j' - знаковое целое число с шириной указателя, родной порядок байтов (как в C intptr_t):

    s = [67305985, -50462977].pack('j*')
    # => "\x01\x02\x03\x04\x00\x00\x00\x00\xFF\xFE\xFD\xFC\xFF\xFF\xFF\xFF"
    s.unpack('j*')
    # => [67305985, -50462977]
    
  • 'J' - беззнаковое целое число с шириной указателя, родной порядок байтов (как в C uintptr_t):

    s = [67305985, 4244504319].pack('J*')
    # => "\x01\x02\x03\x04\x00\x00\x00\x00\xFF\xFE\xFD\xFC\x00\x00\x00\x00"
    s.unpack('J*')
    # => [67305985, 4244504319]
    

Другие директивы целочисленных типов

  • 'U' - символ UTF-8:

    s = [4194304].pack('U*')
    # => "\xF8\x90\x80\x80\x80"
    s.unpack('U*')
    # => [4194304]
    
  • 'w' - целое число в формате BER (см. кодирование BER):

    s = [1073741823].pack('w*')
    # => "\x83\xFF\xFF\xFF\x7F"
    s.unpack('w*')
    # => [1073741823]
    

Модификаторы для директив целочисленных типов

Для следующих директив могут быть добавлены модификаторы '!' или '_' для указания размера, соответствующего родной платформе.

  • 'i', 'I' - C int, всегда родной размер.

  • 's', 'S' - C short.

  • 'l', 'L' - C long.

  • 'q', 'Q' - C long long, если доступно.

  • 'j', 'J' - C intptr_t, всегда родной размер.

Модификаторы родного размера игнорируются для директив, которые всегда используют родной размер.

Модификаторы порядка байтов также могут быть добавлены к указанным выше директивам:

  • '>' - Big-endian.

  • '<' - Little-endian.

Директивы чисел с плавающей точкой

Каждая директива чисел с плавающей точкой определяет упаковку или распаковку одного элемента в массиве ввода или вывода.

Директивы чисел с плавающей точкой одинарной точности

  • 'F' или 'f' - Родной формат:

    s = [3.0].pack('F') # => "\x00\x00@@"
    s.unpack('F')       # => [3.0]
    
  • 'e' - Little-endian:

    s = [3.0].pack('e') # => "\x00\x00@@"
    s.unpack('e')       # => [3.0]
    
  • 'g' - Big-endian:

    s = [3.0].pack('g') # => "@@\x00\x00"
    s.unpack('g')       # => [3.0]
    

Директивы чисел с плавающей точкой двойной точности

  • 'D' или 'd' - Родной формат:

    s = [3.0].pack('D') # => "\x00\x00\x00\x00\x00\x00\b@"
    s.unpack('D')       # => [3.0]
    
  • 'E' - Little-endian:

    s = [3.0].pack('E') # => "\x00\x00\x00\x00\x00\x00\b@"
    s.unpack('E')       # => [3.0]
    
  • 'G' - Big-endian:

    s = [3.0].pack('G') # => "@\b\x00\x00\x00\x00\x00\x00"
    s.unpack('G')       # => [3.0]
    

Директива чисел с плавающей точкой может быть бесконечностью или не числом:

inf = 1.0/0.0                  # => Infinity
[inf].pack('f')                # => "\x00\x00\x80\x7F"
"\x00\x00\x80\x7F".unpack('f') # => [Infinity]

nan = inf/inf                  # => NaN
[nan].pack('f')                # => "\x00\x00\xC0\x7F"
"\x00\x00\xC0\x7F".unpack('f') # => [NaN]

Директивы строк

Каждая директива строки определяет упаковку или распаковку одного байта в строке ввода или вывода.

Директивы бинарных строк

  • 'A' - Произвольная бинарная строка (пробелы до заполнения; количество — это ширина); nil обрабатывается как пустая строка:

    ['foo'].pack('A')    # => "f"
    ['foo'].pack('A*')   # => "foo"
    ['foo'].pack('A2')   # => "fo"
    ['foo'].pack('A4')   # => "foo "
    [nil].pack('A')      # => " "
    [nil].pack('A*')     # => ""
    [nil].pack('A2')     # => "  "
    [nil].pack('A4')     # => "    "
    
    "foo\0".unpack('A')      # => ["f"]
    "foo\0".unpack('A4')     # => ["foo"]
    "foo\0bar".unpack('A10') # => ["foo\x00bar"] # Reads past "\0".
    "foo ".unpack('A')       # => ["f"]
    "foo ".unpack('A4')      # => ["foo"]
    "foo".unpack('A4')       # => ["foo"]
    
    russian = "\u{442 435 441 442}" # => "тест"
    russian.size         # => 4
    russian.bytesize     # => 8
    [russian].pack('A')  # => "\xD1"
    [russian].pack('A*') # => "\xD1\x82\xD0\xB5\xD1\x81\xD1\x82"
    russian.unpack('A')  # => ["\xD1"]
    russian.unpack('A2') # => ["\xD1\x82"]
    russian.unpack('A4') # => ["\xD1\x82\xD0\xB5"]
    russian.unpack('A*') # => ["\xD1\x82\xD0\xB5\xD1\x81\xD1\x82"]
    
  • 'a' - Произвольная бинарная строка (заполнение нулями; количество — это ширина):

    ["foo"].pack('a')    # => "f"
    ["foo"].pack('a*')   # => "foo"
    ["foo"].pack('a2')   # => "fo"
    ["foo\0"].pack('a4') # => "foo\x00"
    [nil].pack('a')      # => "\x00"
    [nil].pack('a*')     # => ""
    [nil].pack('a2')     # => "\x00\x00"
    [nil].pack('a4')     # => "\x00\x00\x00\x00"
    
    "foo\0".unpack('a')     # => ["f"]
    "foo\0".unpack('a4')    # => ["foo\x00"]
    "foo ".unpack('a4')     # => ["foo "]
    "foo".unpack('a4')      # => ["foo"]
    "foo\0bar".unpack('a4') # => ["foo\x00"] # Reads past "\0".
    
  • 'Z' - То же, что и 'a', за исключением того, что ноль добавляется или игнорируется с '*':

    ["foo"].pack('Z*')   # => "foo\x00"
    [nil].pack('Z*')     # => "\x00"
    
    "foo\0".unpack('Z*')    # => ["foo"]
    "foo".unpack('Z*')      # => ["foo"]
    "foo\0bar".unpack('Z*') # => ["foo"] # Does not read past "\0".
    

Директивы битовых строк

  • 'B' - Битовая строка (старший байт первым):

    ['11111111' + '00000000'].pack('B*') # => "\xFF\x00"
    ['10000000' + '01000000'].pack('B*') # => "\x80@"
    
    ['1'].pack('B0') # => ""
    ['1'].pack('B1') # => "\x80"
    ['1'].pack('B2') # => "\x80\x00"
    ['1'].pack('B3') # => "\x80\x00"
    ['1'].pack('B4') # => "\x80\x00\x00"
    ['1'].pack('B5') # => "\x80\x00\x00"
    ['1'].pack('B6') # => "\x80\x00\x00\x00"
    
    "\xff\x00".unpack("B*") # => ["1111111100000000"]
    "\x01\x02".unpack("B*") # => ["0000000100000010"]
    
    "".unpack("B0")     # => [""]
    "\x80".unpack("B1") # => ["1"]
    "\x80".unpack("B2") # => ["10"]
    "\x80".unpack("B3") # => ["100"]
    
  • 'b' - Битовая строка (младший байт первым):

    ['11111111' + '00000000'].pack('b*') # => "\xFF\x00"
    ['10000000' + '01000000'].pack('b*') # => "\x01\x02"
    
    ['1'].pack('b0') # => ""
    ['1'].pack('b1') # => "\x01"
    ['1'].pack('b2') # => "\x01\x00"
    ['1'].pack('b3') # => "\x01\x00"
    ['1'].pack('b4') # => "\x01\x00\x00"
    ['1'].pack('b5') # => "\x01\x00\x00"
    ['1'].pack('b6') # => "\x01\x00\x00\x00"
    
    "\xff\x00".unpack("b*") # => ["1111111100000000"]
    "\x01\x02".unpack("b*") # => ["1000000001000000"]
    
    "".unpack("b0")     # => [""]
    "\x01".unpack("b1") # => ["1"]
    "\x01".unpack("b2") # => ["10"]
    "\x01".unpack("b3") # => ["100"]
    

Директивы шестнадцатеричных строк

  • 'H' - Шестнадцатеричная строка (старший ниббл первым):

    ['10ef'].pack('H*')    # => "\x10\xEF"
    ['10ef'].pack('H0')    # => ""
    ['10ef'].pack('H3')    # => "\x10\xE0"
    ['10ef'].pack('H5')    # => "\x10\xEF\x00"
    
    ['fff'].pack('H3')    # => "\xFF\xF0"
    ['fff'].pack('H4')    # => "\xFF\xF0"
    ['fff'].pack('H5')    # => "\xFF\xF0\x00"
    ['fff'].pack('H6')    # => "\xFF\xF0\x00"
    ['fff'].pack('H7')    # => "\xFF\xF0\x00\x00"
    ['fff'].pack('H8')    # => "\xFF\xF0\x00\x00"
    
    "\x10\xef".unpack('H*')    # => ["10ef"]
    "\x10\xef".unpack('H0')    # => [""]
    "\x10\xef".unpack('H1')    # => ["1"]
    "\x10\xef".unpack('H2')    # => ["10"]
    "\x10\xef".unpack('H3')    # => ["10e"]
    "\x10\xef".unpack('H4')    # => ["10ef"]
    "\x10\xef".unpack('H5')    # => ["10ef"]
    
  • 'h' - Шестнадцатеричная строка (младший ниббл первым):

    ['10ef'].pack('h*') # => "\x01\xFE"
    ['10ef'].pack('h0') # => ""
    ['10ef'].pack('h3') # => "\x01\x0E"
    ['10ef'].pack('h5') # => "\x01\xFE\x00"
    
    ['fff'].pack('h3') # => "\xFF\x0F"
    ['fff'].pack('h4') # => "\xFF\x0F"
    ['fff'].pack('h5') # => "\xFF\x0F\x00"
    ['fff'].pack('h6') # => "\xFF\x0F\x00"
    ['fff'].pack('h7') # => "\xFF\x0F\x00\x00"
    ['fff'].pack('h8') # => "\xFF\x0F\x00\x00"
    
    "\x01\xfe".unpack('h*') # => ["10ef"]
    "\x01\xfe".unpack('h0') # => [""]
    "\x01\xfe".unpack('h1') # => ["1"]
    "\x01\xfe".unpack('h2') # => ["10"]
    "\x01\xfe".unpack('h3') # => ["10e"]
    "\x01\xfe".unpack('h4') # => ["10ef"]
    "\x01\xfe".unpack('h5') # => ["10ef"]
    

Директивы строк-указателей

  • 'P' - Указатель на структуру (строка фиксированной длины):

    s = ['abc'].pack('P')  # => "\xE0O\x7F\xE5\xA1\x01\x00\x00"
    s.unpack('P*')         # => ["abc"]
    ".".unpack("P")        # => []
    ("\0" * 8).unpack("P") # => [nil]
    [nil].pack("P")        # => "\x00\x00\x00\x00\x00\x00\x00\x00"
    
  • 'p' - Указатель на нуль-терминированную строку:

    s = ['abc'].pack('p')  # => "(\xE4u\xE5\xA1\x01\x00\x00"
    s.unpack('p*')         # => ["abc"]
    ".".unpack("p")        # => []
    ("\0" * 8).unpack("p") # => [nil]
    [nil].pack("p")        # => "\x00\x00\x00\x00\x00\x00\x00\x00"
    

Другие директивы строк

  • 'M' - Строка в формате Quoted Printable, кодировка MIME; текстовый режим, но ввод должен использовать LF, и выход LF; (см. RFC 2045):

    ["a b c\td \ne"].pack('M') # => "a b c\td =\n\ne=\n"
    ["\0"].pack('M')           # => "=00=\n"
    
    ["a"*1023].pack('M') == ("a"*73+"=\n")*14+"a=\n"     # => true
    ("a"*73+"=\na=\n").unpack('M') == ["a"*74]           # => true
    (("a"*73+"=\n")*14+"a=\n").unpack('M') == ["a"*1023] # => true
    
    "a b c\td =\n\ne=\n".unpack('M')    # => ["a b c\td \ne"]
    "=00=\n".unpack('M')    # => ["\x00"]
    
    "pre=31=32=33after".unpack('M') # => ["pre123after"]
    "pre=\nafter".unpack('M')       # => ["preafter"]
    "pre=\r\nafter".unpack('M')     # => ["preafter"]
    "pre=".unpack('M')              # => ["pre="]
    "pre=\r".unpack('M')            # => ["pre=\r"]
    "pre=hoge".unpack('M')          # => ["pre=hoge"]
    "pre==31after".unpack('M')      # => ["pre==31after"]
    "pre===31after".unpack('M')     # => ["pre===31after"]
    
  • 'm' - Строка в кодировке Base64; счётчик указывает байты ввода между каждой новой строкой, округляется вниз до ближайшего кратного 3; если счётчик равен нулю, новые строки не добавляются; (см. RFC 4648):

    [""].pack('m')             # => ""
    ["\0"].pack('m')           # => "AA==\n"
    ["\0\0"].pack('m')         # => "AAA=\n"
    ["\0\0\0"].pack('m')       # => "AAAA\n"
    ["\377"].pack('m')         # => "/w==\n"
    ["\377\377"].pack('m')     # => "//8=\n"
    ["\377\377\377"].pack('m') # => "////\n"
    
    "".unpack('m')       # => [""]
    "AA==\n".unpack('m') # => ["\x00"]
    "AAA=\n".unpack('m') # => ["\x00\x00"]
    "AAAA\n".unpack('m') # => ["\x00\x00\x00"]
    "/w==\n".unpack('m') # => ["\xFF"]
    "//8=\n".unpack('m') # => ["\xFF\xFF"]
    "////\n".unpack('m') # => ["\xFF\xFF\xFF"]
    "A\n".unpack('m')    # => [""]
    "AA\n".unpack('m')   # => ["\x00"]
    "AA=\n".unpack('m')  # => ["\x00"]
    "AAA\n".unpack('m')  # => ["\x00\x00"]
    
    [""].pack('m0')             # => ""
    ["\0"].pack('m0')           # => "AA=="
    ["\0\0"].pack('m0')         # => "AAA="
    ["\0\0\0"].pack('m0')       # => "AAAA"
    ["\377"].pack('m0')         # => "/w=="
    ["\377\377"].pack('m0')     # => "//8="
    ["\377\377\377"].pack('m0') # => "////"
    
    "".unpack('m0')     # => [""]
    "AA==".unpack('m0') # => ["\x00"]
    "AAA=".unpack('m0') # => ["\x00\x00"]
    "AAAA".unpack('m0') # => ["\x00\x00\x00"]
    "/w==".unpack('m0') # => ["\xFF"]
    "//8=".unpack('m0') # => ["\xFF\xFF"]
    "////".unpack('m0') # => ["\xFF\xFF\xFF"]
    
  • 'u' - Строка в UU-кодировке:

    [""].pack("u")        # => ""
    ["a"].pack("u")       # => "!80``\n"
    ["aaa"].pack("u")     # => "#86%A\n"
    
    "".unpack("u")        # => [""]
    "#86)C\n".unpack("u") # => ["abc"]
    

Директивы смещений

  • '@' - Начало упаковки со смещения байтов; для упаковки, заполнение нулями или уменьшение при необходимости:

    [1, 2].pack("C@0C")     # => "\x02"
    [1, 2].pack("C@1C")     # => "\x01\x02"
    [1, 2].pack("C@5C")     # => "\x01\x00\x00\x00\x00\x02"
    [*1..5].pack("CCCC@2C") # => "\x01\x02\x05"
    

    Для распаковки, невозможно переместиться за пределы строки:

    "\x01\x00\x00\x02".unpack("C@3C") # => [1, 2]
    "\x00".unpack("@1C")              # => [nil]
    "\x00".unpack("@2C")              # Raises ArgumentError.
    
  • 'X' - Для упаковки, уменьшение для заданного смещения байтов:

    [0, 1, 2].pack("CCXC")    # => "\x00\x02"
    [0, 1, 2].pack("CCX2C")   # => "\x02"
    

    Для распаковки; перемотка позиции распаковки для заданного смещения байтов:

    "\x00\x02".unpack("CCXC") # => [0, 2, 2]
    

    Невозможно переместиться за пределы строки:

    [0, 1, 2].pack("CCX3C")   # Raises ArgumentError.
    "\x00\x02".unpack("CX3C") # Raises ArgumentError.
    
  • 'x' - Начало упаковки после заданного смещения байтов; для упаковки, заполнение нулями при необходимости:

    [].pack("x0")                # => ""
    [].pack("x")                 # => "\x00"
    [].pack("x8")                # => "\x00\x00\x00\x00\x00\x00\x00\x00"
    

    Для распаковки, невозможно переместиться за пределы строки:

    "\x00\x00\x02".unpack("CxC") # => [0, 2]
    "\x00\x00\x02".unpack("x3C") # => [nil]
    "\x00\x00\x02".unpack("x4C") # Raises ArgumentError
    

Ruby Core © 1993–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API