Nodes/m9-prompts-comfyui/StepReplace [m9]
ComfyUI Node

StepReplace [m9]

Search-and-Replace for Prompts, With Dice in It

By MarcusNyne·Created 3 years ago·Updated 3 days ago· 1
StepReplace [m9]
    • text
    text
    search_1
    replace_1
    search_2
    replace_2
    search_3
    replace_3
    search_4
    replace_4
    search_5
    replace_5
    print_outputfalse
    seed_optional0

    Core ComfyUI has a Replace Text node and it's fine - one find, one swap. StepReplace [m9] is what you want when the prompt is a template: five chained replacements applied top to bottom, plus { rose | tulip | peony } choices that collapse to one option at random. Write [SUBJECT] wearing [OUTFIT], standing in [PLACE] once, then swap the placeholders per workflow, or let the node pick from short lists so every run in a batch comes out slightly different.

    It's the pack's least glamorous node and the one I'd put in a randomizer workflow first, because it gives you control the wildcard packs don't: the substitution list is right there in the node, not in a text file you have to maintain.

    How it works

    Each step rewrites the result of the step before it, so a later search can match text an earlier replacement produced - flowerrose on step one, then rosered rose on step two, and you get "a red rose in a vase". An empty search is skipped, so you use only as many of the five as you need, and an empty replace deletes the term.

    Matching is literal and case-insensitive, with a subtlety that's actually useful. A word boundary is added only at an end whose character is a letter, digit or underscore - so cat does not find the cat inside category, but [FIND_THIS] or <lora:foo:0.8> matches wherever it appears, brackets and all. Every occurrence is replaced, not just the first.

    Choices are the interesting part. { one | two | three } collapses to one option; options are trimmed, so {a|b} and { a | b } behave identically; an empty option ({ a | }) is a legal way to sometimes pick nothing; choices nest; and each occurrence draws its own option, so one replacement used three times can give you three different flowers. Braces without a | are left alone, and \{, \|, \} give you literal characters. Choices are resolved as the text is built, not at the end - which is why the second step in that flower example only fires on the runs where rose actually came up.

    The fields

    • text - an input socket. The text lives upstream in a PrimitiveString or another prompt node; this node only rewrites it.
    • search_1 / replace_1 … search_5 / replace_5 - five pairs. search is a single line, replace is multi-line, which is handy when a substitution is a paragraph.
    • print_output - prints what each step did (including 'x' not found, which is the fastest way to debug a step that isn't firing) and the final text.
    • seed_optional - and here the pack inverts its own convention, deliberately.

    Output: text (STRING). Into a CLIP Text Encode, a preview node, or another text node.

    Seeding, because it's the opposite of the rest of the pack

    On the other m9 nodes, an unconnected seed means 0, which means deterministic and cached - you get one variation forever. StepReplace flips that: 0 here means no seed given, so it draws from entropy and re-executes on every queue instead of serving a cached result. That's what makes the example workflow in the repo work - it uses { ... } choices with an incrementing seed and gets a new pick each run out of the box.

    So: default behaviour is "roll every time". Give it any non-zero seed and the run becomes fully reproducible, which is what you want the moment you get a keeper and need the same prompt again. The sensible habit is an incrementing seed primitive rather than a randomize one - same fresh variation, but the number in the box is the one that actually ran, so the log is enough to recover it.

    A worked example

    text:      a flower in a vase
    search_1   flower      replace_1   { rose | tulip | dried lavender }
    search_2   rose        replace_2   red rose, { two | three } blooms
    search_3   vase        replace_3   cracked ceramic vase
    

    Run it twice and you'll get a red-rose branch, a tulip branch, and occasionally a dried lavender branch where step 2 does nothing at all because rose never appeared. That last case is the one people don't anticipate: a step with zero matches is silent unless print_output is on.

    Installing it

    ComfyUI Manager → search m9-prompts-comfyui → install; or:

    cd ComfyUI/custom_nodes
    git clone https://github.com/MarcusNyne/m9-prompts-comfyui
    

    Then restart ComfyUI. No requirements.txt, no downloads, nothing compiled - the pack is stdlib Python plus torch/numpy/Pillow, which you already have. StepReplace is filed under the text category, next to the stock Replace Text node. There's also an embedded workflow in the repo's examples folder (StepReplace_TextPreview_m9.png) you can drag straight in if you'd rather start from a working graph than a blank canvas.

    Categorytext

    Inputs (13)

    NameTypeDefaultDescription
    textSTRING
    search_1STRING
    replace_1STRING
    search_2STRING
    replace_2STRING
    search_3STRING
    replace_3STRING
    search_4STRING
    replace_4STRING
    search_5STRING
    replace_5STRING
    print_outputBOOLEANfalse
    seed_optionaloptINT00–18446744073709550000

    Outputs (1)

    NameTypeDescription
    textSTRING