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.1.0b3.tar.gz (43.5 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.1.0b3-py3-none-any.whl (11.3 kB view details)

Uploaded Python 3

File details

Details for the file takeskip-0.1.0b3.tar.gz.

File metadata

  • Download URL: takeskip-0.1.0b3.tar.gz
  • Upload date:
  • Size: 43.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","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.1.0b3.tar.gz
Algorithm Hash digest
SHA256 d5d01fbb145cc47b2a0889442c4039a33642dba77104130b57cf7181f52e6cce
MD5 a0299ff7319aef3a4d3f434dc3a77d40
BLAKE2b-256 2c183ea6ff052c95195afdeead68984e9bfb106c19f9e62da9b11adb811077e9

See more details on using hashes here.

File details

Details for the file takeskip-0.1.0b3-py3-none-any.whl.

File metadata

  • Download URL: takeskip-0.1.0b3-py3-none-any.whl
  • Upload date:
  • Size: 11.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","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.1.0b3-py3-none-any.whl
Algorithm Hash digest
SHA256 ccd524dbb25d90fe98fd26b8000cca956c1d200c721b4eb1c555b6c7f440ce82
MD5 7602c807971950353fa93ee0da9d5b5b
BLAKE2b-256 bdf84c270ebc584a1299f46b2e23d5042138399ff488a64a097ade2618d70e23

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