Stop merging regexes by hand.

Hand-splicing alternations breaks the moment rules overlap. Intersect, subtract or union patterns as sets and get back one clean pattern, ready for the next call.

Run it on your patterns.

Each card calls the real API. Edit the patterns and compute. No signup.

What do both rules accept?OPEN IN LIVE DEMO →
A =
B =
A B
PATTERN/api/v[12]/(.*/)?users/[0-9]+
Remove one rule from another?OPEN IN LIVE DEMO →
A =
B =
A B
PATTERN.*\.(jpe?|pn)g
Merge overlapping rules into one?OPEN IN LIVE DEMO →
A =
B =
A B
PATTERN[0-9]
OperationNotationAnswersReturns
intersectionABStrings matching all of the patterns.term
unionABStrings matching any of the patterns.term
differenceABStrings in A but not in B.term
complementAEvery string the pattern does not match.term
concatenationA · BPatterns joined in sequence.term
repeatA{n,m}The pattern repeated n to m times.term
determinizedfa(A)The same language as a deterministic FAIR, for a stable string order.term

The whole group, in code.

Every operation above through the official client. The API is plain REST underneath, so any HTTP client works too.

import { RegexSolverClient, Term } from 'regexsolver';

const client = new RegexSolverClient({ apiToken: 'REGEXSOLVER_API_TOKEN' });

// What do both firewalls accept? Intersect them and read the result.
const both = await client.intersection(
  Term.regex("/api/v[12]/.*"),
  Term.regex(".*/users/[0-9]+"),
);
await client.getPattern(both);
// "/api/v[12]/(.*/)?users/[0-9]+"

// Drop gif support from an allowlist: subtract one rule from another
const noGif = await client.difference(
  Term.regex(".*\.(jpe?g|png|gif)"),
  Term.regex(".*\.gif"),
);
await client.getPattern(noGif);
// ".*\.(jpe?|pn)g"

// Everything the validator rejects
const rejected = await client.complement(noGif);

// Results are terms: chain them without re-parsing.
// A term and its complement can never overlap:
await client.isEmpty(await client.intersection(noGif, rejected));
// true