Easy-to-use parser combinators for parsing in pure Python
—
Fundamental parser constructors that form the building blocks for more complex parsers. These functions create Parser objects for matching strings, patterns, and individual characters.
Parse exact string literals with optional case transformation.
def string(s, transform=noop):
"""
Parse an exact string.
Args:
s: String to match exactly
transform: Optional function to transform both input and pattern for comparison
Returns:
Parser: Parser that succeeds if input matches string
"""Parse using regular expressions with support for groups and flags.
def regex(exp, flags=0, group=0):
"""
Parse using a regular expression.
Args:
exp: Regular expression string, bytes, or compiled pattern
flags: Regular expression flags (when exp is string/bytes)
group: Group number, name, or tuple of groups to extract (default 0 for whole match)
Returns:
Parser: Parser that matches the regex pattern
"""Parse individual characters or items based on predicate functions.
def test_char(func, description):
"""
Parse a character that satisfies a predicate function.
Args:
func: Function that takes a character and returns boolean
description: Description for error messages
Returns:
Parser: Parser that succeeds if predicate returns True
"""
def test_item(func, description):
"""
Parse an item that satisfies a predicate function.
Args:
func: Function that takes an item and returns boolean
description: Description for error messages
Returns:
Parser: Parser that succeeds if predicate returns True
"""Parse specific characters or items by equality comparison.
def match_item(item, description=None):
"""
Parse a specific item by equality.
Args:
item: Item to match exactly
description: Optional description (defaults to str(item))
Returns:
Parser: Parser that succeeds if input equals item
"""Parse any of multiple string options, with longest match prioritization.
def string_from(*strings, transform=noop):
"""
Parse any of the given strings (longest first).
Args:
*strings: Variable number of strings to match
transform: Optional function to transform strings for comparison
Returns:
Parser: Parser that matches any of the strings
"""
def char_from(string):
"""
Parse any character from the given string.
Args:
string: String containing allowed characters
Returns:
Parser: Parser that matches any character in string
"""Create parsers that always succeed or fail with specific values.
def success(val):
"""
Parser that always succeeds with the given value.
Args:
val: Value to return on success
Returns:
Parser: Parser that always succeeds
"""
def fail(expected):
"""
Parser that always fails with the given expected message.
Args:
expected: Expected value description for error message
Returns:
Parser: Parser that always fails
"""Parse without consuming input (lookahead).
def peek(parser):
"""
Parse without consuming input.
Args:
parser: Parser to execute for lookahead
Returns:
Parser: Parser that succeeds without advancing position
"""Parse enum values with automatic string conversion.
def from_enum(enum_cls, transform=noop):
"""
Parse enum values from their string representations.
Args:
enum_cls: Enum class to parse values from
transform: Optional function to transform strings for comparison
Returns:
Parser: Parser that matches enum values (longest first)
"""from parsy import string, regex, test_char, string_from, char_from, peek
# Basic string parsing
hello = string('hello')
result = hello.parse('hello') # Returns 'hello'
# Case-insensitive string parsing
insensitive = string('Hello', transform=str.lower)
result = insensitive.parse('HELLO') # Returns 'Hello'
# Regular expression parsing
number = regex(r'\d+').map(int)
result = number.parse('123') # Returns 123
# Regex with groups
quoted = regex(r'"([^"]*)"', group=1)
result = quoted.parse('"hello world"') # Returns 'hello world'
# Character testing
vowel = test_char(lambda c: c in 'aeiou', 'vowel')
result = vowel.parse('a') # Returns 'a'
# Multiple string options
operator = string_from('+', '-', '*', '/')
result = operator.parse('+') # Returns '+'
# Character from set
digit = char_from('0123456789')
result = digit.parse('5') # Returns '5'
# Lookahead
keyword_followed_by_space = string('if') << peek(test_char(str.isspace, 'whitespace'))
result = keyword_followed_by_space.parse('if ') # Returns 'if'
# Enum parsing (Python 3.4+)
from enum import Enum
class Color(Enum):
RED = 'red'
GREEN = 'green'
BLUE = 'blue'
color_parser = from_enum(Color)
result = color_parser.parse('red') # Returns Color.REDInstall with Tessl CLI
npx tessl i tessl/pypi-parsy