feat: add sort_by_length and use_regex options to StringMultiReplace (Issue #11)

This commit is contained in:
BRADSEC
2026-03-03 20:25:08 +10:00
parent f0ba6032c2
commit 5d645958bd
3 changed files with 160 additions and 10 deletions
+17 -9
View File
@@ -17,7 +17,13 @@ class StringMultiReplaceNode:
"label_on": "enabled", "label_off": "disabled",
"tooltip": "When enabled, punctuation marks adjacent to matched text are preserved"}),
"remove_extra_spaces": ("BOOLEAN", {"default": True,
"label_on": "enabled", "label_off": "disabled"})
"label_on": "enabled", "label_off": "disabled"}),
"sort_by_length": ("BOOLEAN", {"default": True,
"label_on": "enabled", "label_off": "disabled",
"tooltip": "When enabled, longer search strings are replaced first to prevent substring clobbering. Disable for input-order replacement."}),
"use_regex": ("BOOLEAN", {"default": False,
"label_on": "enabled", "label_off": "disabled",
"tooltip": "When enabled, search strings are treated as regex patterns instead of literal text"})
}
}
@@ -31,7 +37,7 @@ class StringMultiReplaceNode:
text = re.sub(r'\s{2,}', ' ', text) # Normalize multiple spaces
return text.strip()
def string_replace(self, input_string, replacement_pairs, replacement_delimiter, match_case, match_whole_string, preserve_punctuation, remove_extra_spaces):
def string_replace(self, input_string, replacement_pairs, replacement_delimiter, match_case, match_whole_string, preserve_punctuation, remove_extra_spaces, sort_by_length=True, use_regex=False):
# Create a list of all replacements
replacements = []
for line in replacement_pairs.splitlines():
@@ -48,28 +54,30 @@ class StringMultiReplaceNode:
replacements.append((len(search_str), search_str, replace_str))
# Sort by length in descending order
replacements.sort(reverse=True)
# Sort by length in descending order (longest first to prevent substring clobbering)
if sort_by_length:
replacements.sort(reverse=True)
result = input_string
flags = 0 if match_case else re.IGNORECASE
# Perform replacements
for _, search_str, replace_str in replacements:
escaped = search_str if use_regex else re.escape(search_str)
if match_whole_string:
if preserve_punctuation:
# Match whole words but preserve adjacent punctuation
pattern = r'\b' + re.escape(search_str) + r'\b'
pattern = r'\b' + escaped + r'\b'
else:
# Original behavior: remove punctuation after match
pattern = r'(?:\b|(?<=\s)|^)' + re.escape(search_str) + r'(?:[,;:.])?(?=\s|$)'
pattern = r'(?:\b|(?<=\s)|^)' + escaped + r'(?:[,;:.])?(?=\s|$)'
else:
if preserve_punctuation:
# Simple literal replacement preserving punctuation
pattern = re.escape(search_str)
# Simple replacement preserving punctuation
pattern = escaped
else:
# Original behavior: remove punctuation after match
pattern = re.escape(search_str) + r'(?:[,;:.])?'
pattern = escaped + r'(?:[,;:.])?'
regex = re.compile(pattern, flags=flags)
result = regex.sub(replace_str, result)