diff --git a/src/parsy/__init__.py b/src/parsy/__init__.py index d559de2..c2a0844 100644 --- a/src/parsy/__init__.py +++ b/src/parsy/__init__.py @@ -545,6 +545,27 @@ def string_parser(stream, index): return string_parser +def bstring(expected_bytes: bytes, transform: Callable[[bytes], bytes] = noop) -> Parser: + """Returns a parser that expects the ``expected_bytes`` and produces + that bytestring value. + + Optionally, a transform function can be passed, which will be used on both + the expected bytestring and tested bytestring. + """ + + blen = len(expected_bytes) + transformed_b = transform(expected_bytes) + + @Parser + def bytes_parser(stream, index): + if transform(stream[index : index + blen]) == transformed_b: + return Result.success(index + blen, transformed_b) + else: + return Result.failure(index, expected_bytes) + + return bytes_parser + + def regex(exp: str, flags=0, group: int | str | tuple = 0) -> Parser: """ Returns a parser that expects the given ``exp``, and produces the diff --git a/tests/test_parsy.py b/tests/test_parsy.py index a3908b1..c535047 100644 --- a/tests/test_parsy.py +++ b/tests/test_parsy.py @@ -9,6 +9,7 @@ ParseError, alt, any_char, + bstring, char_from, decimal_digit, digit, @@ -53,6 +54,19 @@ def test_string_transform_2(self): self.assertRaises(ParseError, parser.parse, "dog") + def test_bstring(self): + parser = bstring(b"x") + self.assertEqual(parser.parse(b"x"), b"x") + + self.assertRaises(ParseError, parser.parse, b"y") + + def test_bstring_transform(self): + parser = bstring(b"x", transform=lambda s: s.lower()) + self.assertEqual(parser.parse(b"x"), b"x") + self.assertEqual(parser.parse(b"X"), b"x") + + self.assertRaises(ParseError, parser.parse, b"y") + def test_regex_str(self): parser = regex(r"[0-9]")