Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to split a binary into N bit chunks

Tags:

elixir

given some binary / bitstring

<<1,2,3,4,5>>

how do you split it into n bit chunks.

where n could be 1 bit, 2 bits, etc.

Desired output for 6bits

given above binary in bit form 0000000100000010000000110000010000000101

[<<0::size(6)>>, <<16::size(6)>>, <<8::size(6)>>, <<3::size(6)>>, ...]
like image 256
Keith Nicholas Avatar asked Dec 18 '22 14:12

Keith Nicholas


2 Answers

The key to this is matching the rest of the binary with rest::bitstring (instead of rest::binary), which will also match binaries with partial bytes.

defmodule BitUtils do
  def chunks(binary, n) do
    do_chunks(binary, n, [])
  end

  defp do_chunks(binary, n, acc) when bit_size(binary) <= n do
    Enum.reverse([binary | acc]) 
  end

  defp do_chunks(binary, n, acc) do
    <<chunk::size(n), rest::bitstring>> = binary
    do_chunks(rest, n, [<<chunk::size(n)>> | acc])
  end
end

Usage:

iex> BitUtils.chunks <<1, 2, 3, 4, 5>>, 6
[<<0::size(6)>>, <<16::size(6)>>, <<8::size(6)>>, <<3::size(6)>>,
 <<1::size(6)>>, <<0::size(6)>>, <<5::size(4)>>]
like image 69
Patrick Oscity Avatar answered Dec 28 '22 23:12

Patrick Oscity


A simplest approach is probably to use for comprehensions with binary generator:

for << chunk::size(6) <- binary >>, do: <<chunk::size(6)>>

We can hide it behind a function

def chunk_bits(binary, n) do
  for << chunk::size(n) <- binary >>, do: <<chunk::size(n)>>
end

This gives the desired output:

iex> chunk_bits(<<1, 2, 3, 4, 5>>, 6)
[<<0::size(6)>>, <<16::size(6)>>, <<8::size(6)>>, <<3::size(6)>>,
 <<1::size(6)>>, <<0::size(6)>>]
like image 39
michalmuskala Avatar answered Dec 29 '22 00:12

michalmuskala