Skip to content

Regex Tester — Ruby 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 Ruby implementation — the same logic the interactive tool runs, in a shareable, citable form.

# regex-tester — Ruby port. Match a pattern against text, report every match
# with capture groups and index (Regexp + match-with-position loop).
RegexMatch = Struct.new(:match, :index, :groups)

# JS flag letters -> Regexp constants. Ruby's ^/$ are always line-anchored
# (JS `m` is permanently on); `s` maps to Regexp::MULTILINE (dotall); `u` is
# the default for UTF-8 strings; `y` has no equivalent.
def compile_options(flags)
  opts = 0
  opts |= Regexp::IGNORECASE if flags.include?('i')
  opts |= Regexp::MULTILINE  if flags.include?('s')
  opts
end

def run_regex(pattern, flags, text)
  re = Regexp.new(pattern, compile_options(flags))
  limit = flags.include?('g') ? 2000 : 1
  out = []
  pos = 0
  while out.size < limit && (m = re.match(text, pos))
    out << RegexMatch.new(m[0], m.begin(0), m.captures.map { |g| g || '' })
    pos = m.end(0) + (m.end(0) == m.begin(0) ? 1 : 0) # advance past zero-width
    break if pos > text.length
  end
  out
rescue RegexpError => e
  warn "error: #{e.message}"
  []
end

# Render a result the way the tool's UI does:
# `N. "match" @ index -> [g1, g2]`, or `(none)` when empty.
def format_matches(matches)
  return '(none)' if matches.empty?

  matches.each_with_index.map do |m, i|
    line = %(#{i + 1}. "#{m.match}" @ #{m.index})
    line += " → [#{m.groups.join(', ')}]" unless m.groups.empty?
    line
  end.join("\n")
end

puts format_matches(run_regex(/(\w+)@(\w+)\.(\w+)/, 'g', 'mail@x.com nope bob@test.org'))

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 →