Search by Substring
A \"Does My Prompt Contain X?\" Node, Without Building a Regex Pipeline
- match
- matchList
- count
- found
ComfyUI has no built-in "does this text contain X" check. If you build prompts dynamically - wildcards, tag files, LoRA-triggered words, reusing one caption across steps - you will eventually stare at a blob of text and want to know whether "eyes" is in it. Search by Substring is that question as a node: give it text and a pattern, and it hands back the first match, all matches, a count, and a true/false flag. It's from PhandoNodes, a two-node utility pack that does nothing but string chores (this one plus a text concatenator) and, refreshingly for the ComfyUI ecosystem, has zero dependencies, zero model downloads, and zero setup.
How it actually works
The whole thing is about ten lines of stdlib re, and reading them tells you most of what you need. Both the text and the pattern get lowercased first, so matching is case-insensitive - "Eyes" finds "eyes". Then the pattern gets run through encode().decode("unicode_escape"), which is a roundabout way of saying escape sequences like \n work in your pattern. Then it builds a regex:
regex = rf'\b\w*{pattern}\w*\b'
That means "a whole word containing your substring", not just a bare substring anywhere. Pattern eye matches "eyebrow" and "eyelashes" because they're whole words that contain it. It also means cat matches "location" and "concatenate". Usually that's what you want for tag-style matching; when it's not, it's a gotcha.
The pattern is also dropped into that regex raw, so regex metacharacters do live: ., [, (, | all behave. But the \b\w*…\w*\b wrapper means anchors like ^ and $ mostly won't do what you expect, and the unescape step eats single backslashes - a literal \d in the widget becomes plain d, so true regex classes need \\d. For everyday substring hunting, just don't put punctuation in the pattern.
The inputs and outputs that matter
Three inputs, all plain text:
- text - the blob to search (multiline). Default is literally the word
whole_word, the author's placeholder. Change it. - pattern - the substring to look for. Default
eyes. - default - the fallback string that
matchoutputs when nothing is found. Defaultnot found.
Four outputs, and they're the useful part:
- match - the first hit as a STRING, or your
default. - matchList - every hit as a LIST, so it can feed list-processing nodes.
- count - an INT. Not just "did it find anything" but how many.
- found - a BOOLEAN.
The classic wiring is a text gate: feed found or count into a switch/branching node (Impact Pack and rgthree both have pieces that take a boolean or int input) to steer a conditional path, or use count to scale something like a LoRA strength. match can feed straight back into a prompt node if you're extracting a word to reuse.
Install
ComfyUI Manager: search "ComfyUI-PhandoNodes" and install. Or the old-fashioned way:
cd ComfyUI/custom_nodes
git clone https://github.com/Phando/ComfyUI-PhandoNodes
Then restart ComfyUI. That's genuinely it - there's no requirements.txt and no heavy dependency in the pyproject, so nothing else to pull. If the node doesn't show up, restart ComfyUI properly and check that the pack folder is in custom_nodes; there's not much else that can go wrong with a pure-Python text node. The one thing that bites people is the defaults: drop the node in untouched and it searches the string whole_word for eyes, returns "not found", and looks broken. It isn't. Type your actual text and pattern.
The case thing deserves repeating because it's the trap people hit first: everything is lowercased, so match comes back lowercased too, original casing gone. If you need to round-trip the exact original word, this node isn't the one - it's a search tool, not a picker.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| text | STRING | whole_word | Source to be searched |
| pattern | STRING | eyes | Substring to match (e.g., 'eyes') |
| defaultopt | STRING | not found | Fallback value if 'pattern' is not found |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| match | STRING | — |
| matchList | LIST | — |
| count | INT | — |
| found | BOOLEAN | — |