diff --git a/js/string_essentials.js b/js/string_essentials.js index 2f04366..9065636 100644 --- a/js/string_essentials.js +++ b/js/string_essentials.js @@ -1,5 +1,5 @@ -import { app } from "../../../scripts/app.js"; -import { ComfyWidgets } from "../../../scripts/widgets.js"; +import { app } from "../../scripts/app.js"; +import { ComfyWidgets } from "../../scripts/widgets.js"; // Consistent sizing for all String Essentials nodes const DEFAULT_NODE_WIDTH = 400; diff --git a/pyproject.toml b/pyproject.toml index 971cb30..8a65197 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "comfyui_stringessentials" description = "Simple string manipulation nodes for ComfyUI (strip/remove text strings, search and replace text strings, preview modified string outputs). Useful for modifying text prompts or results from LLM outputs. Nodes will be located under standard Add Node > utils menu. Node names: String Textbox, String Strip, String Multi Replace, String Conditional Append, String Contains Any and String Preview." -version = "2.0.12" +version = "2.0.13" license = {file = "LICENSE"} [project.urls] diff --git a/string_conditional_append_node.py b/string_conditional_append_node.py index bb6608f..1e8447e 100644 --- a/string_conditional_append_node.py +++ b/string_conditional_append_node.py @@ -1,5 +1,3 @@ -import re - class StringConditionalAppendNode: @classmethod def INPUT_TYPES(cls): diff --git a/string_multi_replace_node.py b/string_multi_replace_node.py index ec8e0db..27daf1e 100644 --- a/string_multi_replace_node.py +++ b/string_multi_replace_node.py @@ -95,7 +95,10 @@ class StringMultiReplaceNode: f"StringMultiReplace: invalid regex for search '{search_str}': {e}. " f"Disable use_regex to treat search strings as literal text." ) - result = regex.sub(replace_str, result) + # re.sub always parses the replacement as a template (\1, \g<>); + # in literal mode insert the user's text verbatim instead. + replacement = replace_str if use_regex else replace_str.replace("\\", "\\\\") + result = regex.sub(replacement, result) if remove_extra_spaces: result = self.cleanup_text(result) diff --git a/test_string_nodes.py b/test_string_nodes.py index 9481ce8..06cb32a 100644 --- a/test_string_nodes.py +++ b/test_string_nodes.py @@ -106,6 +106,20 @@ class TestStringNodes(unittest.TestCase): )[0] self.assertEqual(result, "Hello everyone") + def test_replace_literal_backslash_replacement(self): + # With use_regex disabled, replacement text is literal: backslash + # sequences must not be treated as re.sub group references. + result = self.replace_node.string_replace( + input_string="path is X", + replacement_pairs=r"X::C:\1", + replacement_delimiter="::", + match_case=False, + match_whole_string=True, + preserve_punctuation=True, + remove_extra_spaces=False + )[0] + self.assertEqual(result, r"path is C:\1") + def test_replace_multiple_pairs(self): input_string = "The quick brown fox jumps over the lazy dog" replacement_pairs = """quick::slow