Skip to content

Find & Replace — TypeScript source

Find and replace text with literal or regular-expression matching, global replace, case sensitivity, whole-word, and capture-group substitution. Live match counter.

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

// Pure find & replace - no React, no DOM, deterministic.
// Supports literal and regex matching, capture-group substitution, case
// sensitivity, whole-word, and global mode. Never throws.

export interface FindReplaceOptions {
  isRegex: boolean; // default false
  caseSensitive: boolean; // default true
  wholeWord: boolean; // default false
  global: boolean; // default true
  multiline?: boolean; // regex mode only, default false
}

export interface FindReplaceResult {
  result: string;
  matches: number;
  error: string | null;
}

export function escapeRegExp(s: string): string {
  return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

export const defaultOptions: FindReplaceOptions = {
  isRegex: false,
  caseSensitive: true,
  wholeWord: false,
  global: true,
  multiline: false,
};

function buildRegex(find: string, opts: FindReplaceOptions): RegExp | { error: string } {
  let pattern = opts.isRegex ? find : escapeRegExp(find);
  if (opts.wholeWord) pattern = `\\b${pattern}\\b`;
  let flags = opts.global ? 'g' : '';
  if (!opts.caseSensitive) flags += 'i';
  if (opts.isRegex && opts.multiline) flags += 'm';
  try {
    return new RegExp(pattern, flags);
  } catch (e) {
    return { error: (e as Error).message };
  }
}

export function countMatches(
  input: string,
  find: string,
  optsIn: Partial<FindReplaceOptions> = {},
): { matches: number; error: string | null } {
  const opts: FindReplaceOptions = { ...defaultOptions, ...optsIn };
  if (find === '') return { matches: 0, error: null };
  const re = buildRegex(find, opts);
  if (re instanceof RegExp) {
    const m = input.match(re);
    return { matches: m ? m.length : 0, error: null };
  }
  return { matches: 0, error: re.error };
}

export function findReplace(
  input: string,
  find: string,
  replacement: string,
  optsIn: Partial<FindReplaceOptions> = {},
): FindReplaceResult {
  const opts: FindReplaceOptions = { ...defaultOptions, ...optsIn };
  if (find === '') return { result: input, matches: 0, error: null };
  const re = buildRegex(find, opts);
  if (!(re instanceof RegExp)) {
    return { result: input, matches: 0, error: re.error };
  }
  const matches = input.match(re)?.length ?? 0;
  // Rebuild as a fresh regex (the counting match advanced lastIndex on /g).
  const re2 = new RegExp(re.source, re.flags);
  const result = input.replace(re2, replacement);
  return { result, matches, error: null };
}

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 →