Skip to content

Regex Tester — JavaScript source

Test regular expressions against any text with all flags (g/i/m/s/u/y). See every match, its index and capture groups, plus the constructed pattern. 100% in-browser.

This is the JavaScript implementation — the same logic the interactive tool runs, in a shareable, citable form.

/**
 * Regular expression tester: match a pattern against input text and report
 * each match with its capture groups and character index.
 *
 * Language: JavaScript (ES module)
 * CosmoDev polyglot showcase port of the `regex-tester` tool.
 * Ported from src/tools/RegexTester.tsx - display source, part of CosmoDev's
 * polyglot tool pages.
 *
 * Compile the pattern with the chosen JS flags, walk every match, and
 * surface the full match, its index, and the capture groups. Supports the
 * flag set g (global), i (ignore case), m (multiline), s (dotAll),
 * u (unicode), y (sticky). An empty pattern yields no matches and no error;
 * a malformed pattern returns the engine's error message instead of
 * throwing. The global path uses the manual exec loop with zero-width
 * advance and a 2000-match safety cap, exactly as the live island does.
 */

/** The six flags the tool exposes, in toolbar order. */
export const REGEX_FLAGS = ['g', 'i', 'm', 's', 'u', 'y'];

/**
 * Run `pattern` (with `flags`) against `testStr` and collect every match.
 *
 * @param {string} pattern Regular expression source (without delimiters).
 * @param {string} flags Flag letters drawn from REGEX_FLAGS.
 * @param {string} testStr The text to search.
 * @returns {{matches: Array<{match: string, index: number, groups: string[]}>, error: string|null}}
 */
export function runRegex(pattern, flags, testStr) {
  if (!pattern) return { matches: [], error: null };
  try {
    const re = new RegExp(pattern, flags);
    const out = [];
    if (re.global) {
      re.lastIndex = 0;
      let m;
      let guard = 0;
      while ((m = re.exec(testStr)) !== null) {
        out.push({ match: m[0], index: m.index, groups: m.slice(1) });
        if (m[0] === '') re.lastIndex++; // advance past zero-width matches
        if (++guard > 2000) break;
      }
    } else {
      const m = re.exec(testStr);
      if (m) out.push({ match: m[0], index: m.index, groups: m.slice(1) });
    }
    return { matches: out, error: null };
  } catch (e) {
    return { matches: [], error: e instanceof Error ? e.message : 'Invalid regular expression' };
  }
}

/**
 * Render a result the way the tool's UI does: one numbered line per match,
 * `N. "match" @ index → [g1, g2]`, or `(none)` when empty.
 */
export function formatMatches(result) {
  if (result.error) return result.error;
  if (!result.matches.length) return '(none)';
  return result.matches
    .map(
      (m, i) =>
        `${i + 1}. "${m.match}" @ ${m.index}${m.groups.length ? ` → [${m.groups.join(', ')}]` : ''}`,
    )
    .join('\n');
}

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →