Spec-Zone.ru › Ruby 4.0

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

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

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

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

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]
    
  • Целое число 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-битное сетевое целое число, с порядком байтов от старшего к младшему:

    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, с порядком байтов от младшего к старшему:

    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-битное сетевое целое число, с порядком байтов от старшего к младшему:

    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, с порядком байтов от младшего к старшему:

    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]
    
  • 'r' — целое число в кодировке LEB128 со знаком (см. LEB128 со знаком)

    s = [1, 127, -128, 16383, -16384].pack("r*")
    # => "\x01\xFF\x00\x80\x7F\xFF\xFF\x00\x80\x80\x7F"
    s.unpack('r*')
    # => [1, 127, -128, 16383, -16384]
    
  • 'R' — целое число в кодировке LEB128 без знака (см. LEB128 без знака)

    s = [1, 127, 128, 16383, 16384].pack("R*")
    # => "\x01\x7F\x80\x01\xFF\x7F\x80\x80\x01"
    s.unpack('R*')
    # => [1, 127, 128, 16383, 16384]
    
  • '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, всегда нативный размер.

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

К приведённым выше директивам также можно добавить модификаторы порядка байтов:

  • '>' — порядок байтов от старшего к младшему.

  • '<' — порядок байтов от младшего к старшему.

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

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

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

  • 'F' или 'f' — нативный формат:

    s = [3.0].pack('F') # => "\x00\x00@@"
    s.unpack('F')       # => [3.0]
    
  • 'e' — порядок байтов от младшего к старшему:

    s = [3.0].pack('e') # => "\x00\x00@@"
    s.unpack('e')       # => [3.0]
    
  • 'g' — порядок байтов от старшего к младшему:

    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' — порядок байтов от младшего к старшему:

    s = [3.0].pack('E') # => "\x00\x00\x00\x00\x00\x00\b@"
    s.unpack('E')       # => [3.0]
    
  • 'G' — порядок байтов от старшего к младшему:

    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' — кодирование MIME quoted-printable; текстовый режим, но входные данные должны использовать 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–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

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