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, andT4are equivalent - Whitespace is ignored:
t4 s2 r8=t4s2r8 - Parentheses create groups:
(t8s8)4repeats the sequence 4 times - Permutation uses 1-based indexing (bit 1 is the first bit)
- Ranges in permutation are inclusive:
1-4includes 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 operationarray: 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:
- Define command class in
commands.pyinheriting fromCommand - Add grammar rule in
takeskip.lark - Add transformer method in
parser.py - Update documentation
License
takeskip is licensed under the MIT License - see the LICENSE file for details
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file takeskip-0.1.0b4.tar.gz.
File metadata
- Download URL: takeskip-0.1.0b4.tar.gz
- Upload date:
- Size: 44.0 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3c1c88a63e4981d575d4fc7c3adf4afc5fc73c3f9444dbc14eb4b44677095735
|
|
| MD5 |
4a46fe230f87925250b8ed4485d0f050
|
|
| BLAKE2b-256 |
417ec8b58b011ca80a24f23d192d5de362c3f3e31234a0918a400072c98670a4
|
File details
Details for the file takeskip-0.1.0b4-py3-none-any.whl.
File metadata
- Download URL: takeskip-0.1.0b4-py3-none-any.whl
- Upload date:
- Size: 11.6 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
85f7ee3a419b7cdd6a91ffb7c526d8854af186d8eed0f92df1b5b46d4d9ae22b
|
|
| MD5 |
ee09fdbeca7f3d0eabeb7ffc02a080e0
|
|
| BLAKE2b-256 |
34e310016ca51b175d4cf62958544ffceda9fc0b45e5d864ccaae90b51f8272e
|