Skip to main content

Do bit manipulations with take/skip commands

Project description

TakeSkip

A Python library for declarative bit manipulation using an intuitive command syntax.

Overview

TakeSkip provides a domain-specific language for selecting, rearranging, and manipulating bits in binary arrays. Instead of writing complex indexing logic, you can express operations using simple commands like t8s4r8 (take 8 bits, skip 4, reverse 8).

Installation

pip install takeskip

Basic Usage

import numpy as np
from takeskip import takeskip

# Create a binary array (8 bits)
bits = np.array([1, 0, 1, 1, 0, 0, 1, 0], dtype=np.uint8)

# Skip first 2 bits, take next 4
result = takeskip("s2t4", bits)
print(result)  # [1, 1, 0, 0]

# Take 4 bits, reverse next 4
result = takeskip("t4r4", bits)
print(result)  # [1, 0, 1, 1, 0, 1, 0, 0]

Command Reference

Basic Operations

Command Description Example
t<n> Take n bits t8 - take 8 bits
s<n> Skip n bits s4 - skip 4 bits
r<n> Reverse n bits r8 - reverse 8 bits
i<n> Invert n bits (0↔1) i4 - invert 4 bits
ri<n> Reverse and invert n bits ri8 - reverse then invert 8 bits
b<n> Backup pointer n positions b4 - move back 4 positions

Padding Operations

Command Description Example
z<n> Insert n zeros z4 - add 4 zeros
n<n> Insert n ones n4 - add 4 ones
d<binary> Insert literal binary data d101 - add bits 1,0,1

Permutation

Command Description Example
p<indices> Permute using 1-based indices p1,3,5 - select bits 1, 3, 5
p<range> Permute using ranges p1-4 - select bits 1 through 4
p<mixed> Mix indices and ranges p1-4,8,6-5 - complex permutation

Note: Permutation indices are 1-based for user convenience. Ranges are inclusive.

Grouping and Repetition

# Repeat a sequence
bits = np.array([1, 0] * 8, dtype=np.uint8)
result = takeskip("(t4s4)3", bits)  # Repeat "take 4, skip 4" three times

# Group complex operations
result = takeskip("(t2r2s1)4", bits)  # Repeat grouped operations

Advanced Examples

Nibble Swap (swap 4-bit chunks)

bits = np.array([1, 1, 1, 1, 0, 0, 0, 0], dtype=np.uint8)
result = takeskip("s4t4b8t4", bits)  # [0, 0, 0, 0, 1, 1, 1, 1]

Extract Every Other Bit

bits = np.array([1, 0, 1, 0, 1, 0, 1, 0], dtype=np.uint8)
result = takeskip("(t1s1)4", bits)  # [1, 1, 1, 1]

Deinterleave Nibbles

bits = np.array([1, 0, 1, 0, 1, 0, 1, 0], dtype=np.uint8)
result = takeskip("(t1s1)4 b8 (s1t1)4", bits)  # [1, 1, 1, 1, 0, 0, 0, 0]

Complex Permutation

bits = np.array([1, 0, 1, 1, 0, 0, 1, 0], dtype=np.uint8)
# Take bits at positions 1,2,3,4 then 8,7,6,5 (1-based)
result = takeskip("p1-4,8-5", bits)  # [1, 0, 1, 1, 0, 1, 0, 0]

Interleave Pattern with Padding

bits = np.array([1, 1, 1, 1, 0, 0, 0, 0], dtype=np.uint8)
result = takeskip("(t1z1)4", bits)
# [1, 0, 1, 0, 1, 0, 1, 0] - interleaved with zeros

Remnant Handling

Control what happens to remaining bits after commands execute:

bits = np.array([1, 0, 1, 1, 0, 0, 1, 0], dtype=np.uint8)

# Default: discard remaining bits
result = takeskip("t4", bits, remnant="remove")  # [1, 0, 1, 1]

# Keep remaining bits
result = takeskip("t4", bits, remnant="keep")  # [1, 0, 1, 1, 0, 0, 1, 0]

# Pad with zeros to original length
result = takeskip("t4", bits, remnant="pad")  # [1, 0, 1, 1, 0, 0, 0, 0]

Multi-dimensional Arrays

TakeSkip operates on the last axis of multi-dimensional arrays:

# 2D array: 3 rows of 8 bits each
bits = np.array([
    [1, 0, 1, 1, 0, 0, 1, 0],
    [0, 1, 0, 1, 1, 1, 0, 1],
    [1, 1, 0, 0, 1, 0, 1, 1],
], dtype=np.uint8)

result = takeskip("s2t4", bits)
# [[1, 1, 0, 0],
#  [0, 1, 1, 1],
#  [0, 0, 1, 0]]

Use Cases

  • Data packing/unpacking: Extract fields from packed binary formats
  • Protocol parsing: Parse binary protocols with field alignment
  • Bit manipulation: Rearrange bits in encryption/encoding operations

Command Chaining

Commands are executed left-to-right with a maintained pointer. The pointer must stay within [0, array_length] after each command; a ValueError is raised if Backup moves before the start or Skip/Take moves past the end.

bits = np.array([1, 0, 1, 1, 0, 0, 1, 0], dtype=np.uint8)

# Pointer starts at 0
# t2: take bits 0-1 -> [1,0], pointer now at 2
# s2: skip bits 2-3, pointer now at 4  
# t4: take bits 4-7 -> [0,0,1,0], pointer now at 8
result = takeskip("t2s2t4", bits)  # [1, 0, 0, 0, 1, 0]

Syntax Notes

  • Commands are case-insensitive: T4, t4, and T4 are equivalent
  • Whitespace is ignored: t4 s2 r8 = t4s2r8
  • Parentheses create groups: (t8s8)4 repeats the sequence 4 times
  • Permutation uses 1-based indexing (bit 1 is the first bit)
  • Ranges in permutation are inclusive: 1-4 includes bits 1, 2, 3, and 4

API Documentation

Main Function

def takeskip(
    command: str,
    array: npt.NDArray[np.uint8],
    *,
    remnant: Literal["remove", "keep", "pad"] = "remove",
) -> np.ndarray

Parameters:

  • command: Command string expressing the operation
  • array: Target numpy array (dtype=uint8, values 0 or 1)
  • remnant: How to handle remaining bits ("remove", "keep", or "pad")

Returns:

  • Numpy array with same dtype, modified according to commands

Raises:

  • ValueError: Invalid remnant argument or invalid command syntax

Contributing

When adding new commands:

  1. Define command class in commands.py inheriting from Command
  2. Add grammar rule in takeskip.lark
  3. Add transformer method in parser.py
  4. Update documentation

License

takeskip is licensed under the MIT License - see the LICENSE file for details

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

takeskip-0.2.0.tar.gz (44.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

takeskip-0.2.0-py3-none-any.whl (11.8 kB view details)

Uploaded Python 3

File details

Details for the file takeskip-0.2.0.tar.gz.

File metadata

  • Download URL: takeskip-0.2.0.tar.gz
  • Upload date:
  • Size: 44.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for takeskip-0.2.0.tar.gz
Algorithm Hash digest
SHA256 392693369a7aa343a788192b95f079f59b548984b65b42643ea798432f54c7d9
MD5 d0fc2858e7ed3a2ee0b33db390cddaf7
BLAKE2b-256 7c48778a01d9f7cd84c46a248f8c4971c745de7c74d564715b2ecdb6f9aff97e

See more details on using hashes here.

File details

Details for the file takeskip-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: takeskip-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 11.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for takeskip-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7e3fa2457904bd1dc0d6091f8d246667a223ae2d700d82100a85b9df51855e59
MD5 5581221f7c58f538ad9667415c062eed
BLAKE2b-256 88794f460742fe412ae091b44344c114d63416ba3af974de621cefafd96d7309

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page