diff --git a/dahlia/constants.py b/dahlia/constants.py index 363fd87..be2297c 100644 --- a/dahlia/constants.py +++ b/dahlia/constants.py @@ -131,3 +131,5 @@ 8: "\033[48;5;{}m", 24: "\033[48;2;{}m", } + +REGEX_BREAKING_MARKERS = set("^$.|()[]\\*+?") diff --git a/dahlia/utils.py b/dahlia/utils.py index bc555c8..4e4ae52 100644 --- a/dahlia/utils.py +++ b/dahlia/utils.py @@ -3,7 +3,12 @@ import re from typing import TYPE_CHECKING -from dahlia.constants import ANSI_REGEX, CODE_REGEXES, NO_GROUP_CODES +from dahlia.constants import ( + ANSI_REGEX, + CODE_REGEXES, + NO_GROUP_CODES, + REGEX_BREAKING_MARKERS, +) if TYPE_CHECKING: from collections.abc import Iterator @@ -52,4 +57,6 @@ def _with_marker(marker: str) -> list[re.Pattern[str]]: if len(marker) != 1: msg = "The marker has to be a single character" raise ValueError(msg) + if marker in REGEX_BREAKING_MARKERS: + marker = "\\" + marker return [re.compile(marker + i) for i in CODE_REGEXES] diff --git a/tests/test_api.py b/tests/test_api.py index 72d09f6..44d7ea4 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -2,6 +2,7 @@ import pytest +from dahlia.constants import REGEX_BREAKING_MARKERS from dahlia.lib import Dahlia, Depth @@ -46,13 +47,21 @@ def test_conversion(depth: Depth, string: str, expected: str) -> None: ("x", "&ee§ee§§_4x"), ], ) -def test_markers(marker: str, expected: str) -> None: +def test_marker_clashing(marker: str, expected: str) -> None: assert ( Dahlia(marker=marker, auto_reset=False, depth=Depth.LOW).convert("&ee§ee§§_4x") == expected ) +@pytest.mark.parametrize("marker", REGEX_BREAKING_MARKERS) +def test_regex_markers(marker: str) -> None: + assert ( + Dahlia(depth=Depth.LOW, marker=marker).convert(f"{marker}4xe5") + == "\x1b[31mxe5\x1b[0m" + ) + + @pytest.mark.parametrize("marker", ["", "&&"]) def test_invalid_marker(marker: str) -> None: with pytest.raises(ValueError, match="The marker has to be a single character"):