diff --git a/src/ytdl_sub/script/functions/__init__.py b/src/ytdl_sub/script/functions/__init__.py index 5c23fa8b..c0f83784 100644 --- a/src/ytdl_sub/script/functions/__init__.py +++ b/src/ytdl_sub/script/functions/__init__.py @@ -6,6 +6,7 @@ from ytdl_sub.script.functions.conditional_functions import ConditionalFunctions from ytdl_sub.script.functions.error_functions import ErrorFunctions from ytdl_sub.script.functions.map_functions import MapFunctions from ytdl_sub.script.functions.numeric_functions import NumericFunctions +from ytdl_sub.script.functions.regex_functions import RegexFunctions from ytdl_sub.script.functions.string_functions import StringFunctions from ytdl_sub.script.types.resolvable import Resolvable from ytdl_sub.script.utils.exceptions import FunctionDoesNotExistRuntimeException @@ -19,6 +20,7 @@ class Functions( MapFunctions, BooleanFunctions, ErrorFunctions, + RegexFunctions, ): @classmethod def is_built_in(cls, name: str) -> bool: diff --git a/src/ytdl_sub/script/functions/regex_functions.py b/src/ytdl_sub/script/functions/regex_functions.py new file mode 100644 index 00000000..c933a623 --- /dev/null +++ b/src/ytdl_sub/script/functions/regex_functions.py @@ -0,0 +1,36 @@ +import re +from typing import AnyStr +from typing import Match + +from ytdl_sub.script.types.array import Array +from ytdl_sub.script.types.array import ResolvedArray +from ytdl_sub.script.types.resolvable import String + + +def _re_output_to_array(re_out: Match[AnyStr] | None) -> ResolvedArray: + if re_out is None: + return ResolvedArray([]) + + return ResolvedArray( + list([String(re_out.string)]) + list(String(group) for group in re_out.groups()) + ) + + +class RegexFunctions: + @staticmethod + def regex_match(regex: String, string: String) -> Array: + """ + Cast to String. + """ + return _re_output_to_array(re.match(regex.value, string.value)) + + @staticmethod + def regex_search(regex: String, string: String) -> Array: + """ + Cast to String. + """ + return _re_output_to_array(re.search(regex.value, string.value)) + + @staticmethod + def regex_fullmatch(regex: String, string: String) -> Array: + return _re_output_to_array(re.fullmatch(regex.value, string.value)) diff --git a/tests/unit/script/functions/test_regex_functions.py b/tests/unit/script/functions/test_regex_functions.py new file mode 100644 index 00000000..b0ca2e16 --- /dev/null +++ b/tests/unit/script/functions/test_regex_functions.py @@ -0,0 +1,45 @@ +import pytest +from unit.script.conftest import single_variable_output + +from ytdl_sub.script.script import Script + + +class TestNumericFunctions: + @pytest.mark.parametrize( + "values, expected_output", + [ + ("'ow', 'lower'", []), + ("'.*ow.*', 'lower'", ["lower"]), + ("'.*(ow).*', 'lower'", ["lower", "ow"]), + ("'(.*)(ow)(.*)', 'lower'", ["lower", "l", "ow", "er"]), + ], + ) + def test_regex_match(self, values: str, expected_output: str): + output = single_variable_output(f"{{%regex_match({values})}}") + assert output == expected_output + + @pytest.mark.parametrize( + "values, expected_output", + [ + ("'ow', 'lower'", ["lower"]), + ("'.*ow.*', 'lower'", ["lower"]), + ("'.*(ow).*', 'lower'", ["lower", "ow"]), + ("'(.*)(ow)(.*)', 'lower'", ["lower", "l", "ow", "er"]), + ], + ) + def test_regex_search(self, values: str, expected_output: str): + output = single_variable_output(f"{{%regex_search({values})}}") + assert output == expected_output + + @pytest.mark.parametrize( + "values, expected_output", + [ + ("'ow', 'lower'", []), + ("'.*ow.*', 'lower'", ["lower"]), + ("'.*(ow).*', 'lower'", ["lower", "ow"]), + ("'(.*)(ow)(.*)', 'lower'", ["lower", "l", "ow", "er"]), + ], + ) + def test_regex_fullmatch(self, values: str, expected_output: str): + output = single_variable_output(f"{{%regex_fullmatch({values})}}") + assert output == expected_output