File size: 4,129 Bytes
5b97e57
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import re
from typing import Tuple

HELP_TEXT = """Examples:

Find => Replace pairs (one per line):

hello => hi

world => earth

old => new



Empty replacement removes text:

remove_this => 



Note: Replacements are applied sequentially.

If 'A => B' and 'B => C' are pairs, 'A' will become 'C'."""

REGEX_HELP = """Common Patterns:

. = any character

.* = any characters

\\d = digit

\\w = word character

[abc] = a, b, or c

(text) = capture group

"""

class SimpleStringReplace:
    @classmethod
    def INPUT_TYPES(s):
        return {
            "required": {
                "text": ("STRING", {"forceInput": True}),
                "find_replace_pairs": ("STRING", {
                    "multiline": True,
                    "default": "find => replace\nold => new",
                    "placeholder": HELP_TEXT
                }),
            },
            "optional": {
                "whole_word_match": ("BOOLEAN", {"default": False}),
            }
        }
    
    RETURN_TYPES = ("STRING",)
    FUNCTION = "replace"
    CATEGORY = "string"

    def replace(self, text: str, find_replace_pairs: str, whole_word_match: bool = False) -> Tuple[str]:
        if not text:
            return (text,)

        result = text
        lines = [line.strip() for line in find_replace_pairs.split('\n') if line.strip()]
        
        for line in lines:
            if '=>' not in line:
                continue
                
            find, replace = line.split('=>', 1)
            find = find.strip()
            replace = replace.strip()
            
            if find:
                if whole_word_match:
                    pattern = r'\b' + re.escape(find) + r'\b'
                    result = re.sub(pattern, replace, result)
                else:
                    result = result.replace(find, replace)
        
        return (result,)

class RegexStringReplace:
    @classmethod
    def INPUT_TYPES(s):
        return {
            "required": {
                "text": ("STRING", {"forceInput": True}),
                "pattern": ("STRING", {
                    "multiline": True,
                    "placeholder": REGEX_HELP
                }),
                "replacement": ("STRING", {"multiline": True}),
            },
            "optional": {
                "case_insensitive": ("BOOLEAN", {"default": False}),
                "test_mode": ("BOOLEAN", {"default": False}),
            }
        }
    
    RETURN_TYPES = ("STRING",)
    FUNCTION = "replace"
    CATEGORY = "string"

    def replace(self, text: str, pattern: str, replacement: str, 

                case_insensitive: bool = False, test_mode: bool = False) -> Tuple[str]:
        if not text or not pattern:
            return (text,)
            
        try:
            flags = re.IGNORECASE if case_insensitive else 0
            
            if test_mode:
                # In test mode, highlight matches without replacing
                matches = re.finditer(pattern, text, flags=flags)
                result = text
                highlight_start = ">>>"
                highlight_end = "<<<"
                
                # Work backwards through matches to not mess up positions
                matches = list(matches)
                for match in reversed(matches):
                    start, end = match.span()
                    result = result[:start] + highlight_start + result[start:end] + highlight_end + result[end:]
                    
                return (result,)
            else:
                result = re.sub(pattern, replacement, text, flags=flags)
                return (result,)
                
        except re.error as e:
            return (f"Error in regex pattern: {str(e)}\nOriginal text:\n{text}",)

NODE_CLASS_MAPPINGS = {
    "SimpleStringReplace": SimpleStringReplace,
    "RegexStringReplace": RegexStringReplace
}

NODE_DISPLAY_NAME_MAPPINGS = {
    "SimpleStringReplace": "Simple String Replace",
    "RegexStringReplace": "Regex String Replace"
}