Files
scofano-comfy-text-stats/character_search_replace.py
scofanoandClaude Sonnet 4.6 22621d6fe9 feat: multi-character search/replace with pipe separator (v1.6.0)
Replace the single-character rule format with a pipe-delimited format:
  search_string|replacement_string

Both sides can now be arbitrary-length strings, enabling rules like
`,10|,` to replace multi-character sequences. Lines without `|` are
silently skipped. Default replacement list and README updated to match.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 23:03:43 -03:00

101 lines
2.4 KiB
Python
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# character_search_replace.py
from typing import List, Tuple
DEFAULT_REPLACEMENTS = (
"“|\"\n"
"”|\"\n"
"„|\"\n"
"«|\"\n"
"»|\"\n"
"‘|'\n"
"’|'\n"
"‚|'\n"
"´|'\n"
"`|'\n"
"–|-\n"
"—|, \n"
"−|-\n"
"‐|-\n"
"‑|-\n"
"•|-\n"
"·|-\n"
"*|\n"
" |_\n"
"…|..."
)
def _parse_replacement_rules(replacements: str) -> List[Tuple[str, str]]:
rules: List[Tuple[str, str]] = []
for line in replacements.splitlines():
if not line:
continue
if "|" not in line:
continue
search, replace = line.split("|", 1)
if search:
rules.append((search, replace))
return rules
def _replace_characters(text: str, replacements: str) -> str:
result = text
for search, replace in _parse_replacement_rules(replacements):
result = result.replace(search, replace)
return result
class CharacterSearchReplace:
"""
Replaces strings using a multiline mapping list.
Each non-empty line defines one rule using a `|` separator:
search_string|replacement_string
Everything before the first `|` is the search target (may be multiple
characters). Everything after is the replacement (may be empty, to delete).
Lines without `|` are silently skipped.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"text": ("STRING", {"multiline": True, "default": ""}),
"replacements": (
"STRING",
{"multiline": True, "default": DEFAULT_REPLACEMENTS},
),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("processed_text",)
FUNCTION = "process"
CATEGORY = "Text/Utils"
OUTPUT_NODE = False
def process(self, text: str, replacements: str) -> Tuple[str]:
if text is None:
text = ""
if not isinstance(text, str):
text = str(text)
if replacements is None:
replacements = ""
if not isinstance(replacements, str):
replacements = str(replacements)
return (_replace_characters(text, replacements),)
@classmethod
def IS_CHANGED(cls, **kwargs) -> float:
text = kwargs.get("text", "") or ""
replacements = kwargs.get("replacements", "") or ""
return float(len(text) + len(replacements))