Skip to main content

Text.Regex

Text.Regex is a vendored copy of the regex-compat-tdfa package, included directly in the gwern.net codebase to avoid Cabal dependency versioning conflicts.

Pathbuild/Text/Regex.hs
LanguageHaskell
Lines202
Sourcebuild/Text/Regex.hs
at 406d3e423

Read this when Use this page when tracing the Haskell build pipeline, generators, metadata code, or backend utility behavior around Text.Regex.

Overview

Text.Regex is a vendored copy of the regex-compat-tdfa package, included directly in the gwern.net codebase to avoid Cabal dependency versioning conflicts. It provides a simple, high-level interface for regular expression matching and substitution using the TDFA (Tagged Deterministic Finite Automaton) regex engine.

The module offers POSIX "extended" regular expression syntax (similar to egrep) with configurable options for case sensitivity and multiline matching. It wraps the lower-level Text.Regex.TDFA and Text.Regex.Base modules into a convenient API used throughout the build system.

This vendored approach ensures stable regex behavior regardless of external package updates or version conflicts in the Haskell ecosystem.


Public API

mkRegex :: String -> Regex

Creates a compiled regular expression with default options (multiline mode enabled, case-sensitive).

let pattern = mkRegex "^[A-Z][a-z]+ [0-9]{4}$"
-- Matches lines like "Smith 2020"

Default options:

  • newSyntax = True (extended regex syntax)
  • multiline = True (^/$ match line boundaries)
  • Case-sensitive matching

mkRegexWithOpts :: String -> Bool -> Bool -> Regex

Creates a compiled regex with explicit multiline and case-sensitivity options.

mkRegexWithOpts pattern singleLine caseSensitive

Parameters:

  • singleLine: When True, ^ and $ match individual line boundaries; . does not match newlines
  • caseSensitive: When True, matching is case-sensitive
-- Case-insensitive, single-line mode
let pattern = mkRegexWithOpts "[a-z]+" True False

matchRegex :: Regex -> String -> Maybe [String]

Matches a regex against a string, returning captured subgroups.

matchRegex (mkRegex "([A-Z]+) ([0-9]+)") "ABC 123"
-- → Just ["ABC", "123"]

matchRegex (mkRegex "foo") "bar"
-- → Nothing

matchRegexAll :: Regex -> String -> Maybe (String, String, String, [String])

Full match information including context around the match.

matchRegexAll (mkRegex "[0-9]+") "foo 123 bar"
-- → Just ("foo ", "123", " bar", [])
-- ^before ^match ^after ^subgroups

Returns: Just (beforeMatch, matched, afterMatch, subgroupMatches) or Nothing

subRegex :: Regex -> String -> String -> String

Replaces all occurrences of a pattern with a replacement string.

subRegex (mkRegex "[0-9]+") "a1b2c3" "X"
-- → "aXbXcX"

Replacement syntax:

  • \0 - entire match
  • \1, \2, ... - captured subgroups
  • \\ - literal backslash
subRegex (mkRegex "([a-z]+)([0-9]+)") "foo123" "\\2-\\1"
-- → "123-foo"

Note: Does not advance on empty matches (matches original Text.Regex behavior).

splitRegex :: Regex -> String -> [String]

Splits a string on a delimiter pattern.

splitRegex (mkRegex ", *") "a, b,  c"
-- → ["a", "b", "c"]

splitRegex (mkRegex "::") "a::b::c"
-- → ["a", "b", "c"]

(Note: POSIX ERE as implemented by regex-tdfa does not support Perl-style shorthand classes like \s; use explicit character classes such as [ \t] instead.)

Warning: Produces infinite list if the regex matches empty strings.


Why Vendored

The comment at the top of the file explains:

GWERN.NET: VENDORED FROM regex-compat-tdfa-0.95.1.4 DUE TO CABAL DEPENDENCY VERSIONING PROBLEMS

Haskell's package ecosystem can have version conflicts when multiple packages require different versions of the same dependency. By vendoring this module, gwern.net:

  1. Avoids dependency resolution failures during builds
  2. Ensures consistent regex behavior across all build environments
  3. Eliminates external package update surprises

Usage in Codebase

The direct importers are:

  • Utils.hs: wraps mkRegex/subRegex in its sed/sedMany helpers, which are used pervasively across the codebase (the source warns that regex-compat-tdfa is required for Unicode-safe search-and-replace)
  • Typography.hs: typographic pattern matching/rewrites
  • Metadata/Format.hs and Metadata/Date.hs: abstract/metadata cleanup and date parsing
  • Annotation/Gwernnet.hs: extracting structured data from scraped content
  • Config/LinkSuggester.hs and Test.hs: config patterns and regex-validity testing

(Note: LinkMetadata.hs does not import this module directly; it gets regex functionality indirectly via Utils.hs.)


Configuration

Listed in gwernnet.cabal as an exposed library module:

exposed-modules:
...
Text.Regex
...

Depends on:

  • regex-base - Abstract regex interface
  • regex-tdfa - TDFA implementation

See Also
  • Typography.hs - Uses regex for typographic rewrites
  • Utils.hs - Wraps this module in the widely-used sed/sedMany helpers
  • gwernnet.cabal - Build configuration listing this module