Comby-like structural search and rewrite for code
A Python implementation of Comby patterns for structural code matching and transformation.
from pycomby import pycomby
# Extract matches
matches = pycomby("Hello, world!", "Hello, :[greeting:word]!")
# [{'greeting': 'world'}]
# Rewrite code
code = "foo(bar(1, 2))"
result = pycomby(code, ":[func:()]", "[CALL :[func]]")
# "[CALL foo(bar(1, 2))]"# Extract
echo "John is 30. Jane is 25." | pycomby ':[name:word] is :[age:digit]'
{"name":"John","age":"30"}
{"name":"Jane","age":"25"}
# Replace
echo "John is 30" | pycomby ':[name:word] is :[age:digit]' 'Person: :[name.upper]'
Person: JOHN- Balanced delimiters – Match
(),[],{}with proper nesting (no regex hacks) - Macros –
:[x:word],:[x:digit],:[x:num]for common patterns - Structural macros –
:[x:()]for balanced parentheses,:[x:(_)]for content only - Optional holes –
:[x?]or:[x:word?]for optional matching - Regex constraints –
:[x~\d{3}]for custom patterns - Transformations – Chain operations:
:[path.basename.upper] - Comment/string aware – Ignores delimiters inside strings and comments
git clone https://github.com/bardo84/pycomby.git
cd pycomby
pip install -e .Then use:
pycomby [OPTIONS] PATTERN [REPLACEMENT] < input.txtSee SYNTAX.md for complete documentation.
| Pattern | Matches |
|---|---|
:[name] |
Any text, captured as name |
:[_] |
Any text, not captured |
... |
Any text (shorthand for :[_]) |
:[x:word] |
Word characters (\w+) |
:[x:digit] |
Digits (\d+) |
:[x:num] |
Numbers (int, float, scientific) |
:[x:()] |
Balanced parentheses with content |
:[x:(_)] |
Content inside parentheses only |
:[x~[a-z]+] |
Custom regex pattern |
:[x?] |
Optional match |
# String operations
pycomby(text, pattern, ":[name.upper]") # Uppercase
pycomby(text, pattern, ":[name.lower]") # Lowercase
pycomby(text, pattern, ":[name.capitalize]") # Capitalize
# Arithmetic (on numbers)
pycomby(text, pattern, ":[num.inc]") # +1
pycomby(text, pattern, ":[num.dec]") # -1
# Path operations
pycomby(text, pattern, ":[path.basename]") # Filename without extension
pycomby(text, pattern, ":[path.extension]") # File extension
pycomby(text, pattern, ":[path.filename]") # Full filename
# Chain operations
pycomby(text, pattern, ":[x.basename.upper]") # basename, then uppercase- Code refactoring – Find and rewrite patterns across files
- API migration – Update function calls (e.g.,
old_api()→new_api()) - Linting – Detect problematic patterns in code
- Code generation – Template-based transformations
- Log parsing – Extract structured data from unformatted text
python -m unittest discover -p "*test*.py" -vAll 28 tests pass. See pycomby_test.py and test_cli.py.
Unlike regex engines, pycomby:
- Tokenizes patterns into literals and holes
- Backtracks intelligently to find matches
- Handles structure with a stack-based scanner for balanced delimiters
This means you get:
- No regex escaping needed for literal text
- Proper handling of nested delimiters (unlike
\(.*\)) - Whitespace flexibility without explicit patterns
- Backtracking can be quadratic in worst case (use specific patterns when possible)
- Structural macros are language-agnostic (don't skip language-specific comments)
- Entire input loaded into memory
Contributions welcome! See CONTRIBUTING.md.
MIT License. See LICENSE.
Related: Comby – The original Comby implementation