diff --git a/docs/source/config_reference/scripting/scripting_functions.rst b/docs/source/config_reference/scripting/scripting_functions.rst index ebf238b33..a12b0ebd2 100644 --- a/docs/source/config_reference/scripting/scripting_functions.rst +++ b/docs/source/config_reference/scripting/scripting_functions.rst @@ -710,6 +710,24 @@ titlecase :description: Capitalize each word in the string. +unescape +~~~~~~~~ +:spec: ``unescape(string: String) -> String`` + +:description: + Unescape symbols like newlines or tabs to their true form. + +:usage: + +.. code-block:: python + + { + %unescape( "Hello\nWorld" ) + } + + # Hello + # World + upper ~~~~~ :spec: ``upper(string: String) -> String`` diff --git a/src/ytdl_sub/script/functions/string_functions.py b/src/ytdl_sub/script/functions/string_functions.py index 0819a6f53..c2977db0f 100644 --- a/src/ytdl_sub/script/functions/string_functions.py +++ b/src/ytdl_sub/script/functions/string_functions.py @@ -143,3 +143,22 @@ def pad_zero(numeric: Numeric, length: Integer) -> String: length=length, char=String("0"), ) + + @staticmethod + def unescape(string: String) -> String: + """ + :description: + Unescape symbols like newlines or tabs to their true form. + + :usage: + + .. code-block:: python + + { + %unescape( "Hello\\nWorld" ) + } + + # Hello + # World + """ + return String(string.value.encode("utf-8").decode("unicode_escape")) diff --git a/src/ytdl_sub/script/parser.py b/src/ytdl_sub/script/parser.py index 0f844e34f..737d6ffa2 100644 --- a/src/ytdl_sub/script/parser.py +++ b/src/ytdl_sub/script/parser.py @@ -301,16 +301,8 @@ def _parse_string(self, str_open_token: str) -> String: self._pos += len(str_open_token) return String(value=string_value) - # Read literal "\n" as newlines - if self._read(increment_pos=False, length=2) == "\\n": - string_value += "\n" - self._pos += 2 - elif self._read(increment_pos=False, length=2) == "\\t": - string_value += "\t" - self._pos += 2 - else: - self._pos += 1 - string_value += ch + self._pos += 1 + string_value += ch raise STRINGS_NOT_CLOSED diff --git a/tests/unit/script/functions/test_string_functions.py b/tests/unit/script/functions/test_string_functions.py index ea3d441d9..a5a2961d9 100644 --- a/tests/unit/script/functions/test_string_functions.py +++ b/tests/unit/script/functions/test_string_functions.py @@ -129,18 +129,18 @@ def test_contains_any(self, value, expected_output): @pytest.mark.parametrize( "input_string, split, max_split, expected_output", [ - ("no splits", " | ", None, ["no splits"]), - ("one | split", " | ", None, ["one", "split"]), - ("max | split | one", " | ", 1, ["max", "split | one"]), - ("multiline\ndescription", "\\n", None, ["multiline", "description"]), + ("no splits", "' | '", None, ["no splits"]), + ("one | split", "' | '", None, ["one", "split"]), + ("max | split | one", "' | '", 1, ["max", "split | one"]), + ("multiline\ndescription", "%unescape('\\n')", None, ["multiline", "description"]), ], ) def test_split( self, input_string: str, split: str, max_split: Optional[int], expected_output: List[str] ): if max_split: - output = single_variable_output(f"{{%split('{input_string}', '{split}', {max_split})}}") + output = single_variable_output(f"{{%split('{input_string}', {split}, {max_split})}}") else: - output = single_variable_output(f"{{%split('{input_string}', '{split}')}}") + output = single_variable_output(f"{{%split('{input_string}', {split})}}") assert output == expected_output diff --git a/tests/unit/script/types/test_string.py b/tests/unit/script/types/test_string.py index 08700ace6..11ad9065b 100644 --- a/tests/unit/script/types/test_string.py +++ b/tests/unit/script/types/test_string.py @@ -46,14 +46,22 @@ def test_string_not_arg(self, string: str): ("{%string('backslash \\\\')}", "backslash \\\\"), ("{%string('''triple quote with \" ' \\''')}", "triple quote with \" ' \\"), ('{%string("""triple quote with " \' \\""")}', "triple quote with \" ' \\"), - ("{%string('literal \\n newlines')}", "literal \n newlines"), ("{%string('supports \t tabs')}", "supports \t tabs"), - ("{%string('literal \\t tabs')}", "literal \t tabs"), ], ) def test_string(self, string: str, expected_string: str): assert single_variable_output(string) == expected_string + @pytest.mark.parametrize( + "string, expected_string", + [ + ("{%unescape('literal \\n newlines')}", "literal \n newlines"), + ("{%unescape('literal \\t tabs')}", "literal \t tabs"), + ], + ) + def test_unescape(self, string: str, expected_string: str): + assert single_variable_output(string) == expected_string + def test_null_is_empty_string(self): assert Script({"out": "{%string(null)}"}).resolve() == ScriptOutput({"out": String("")})