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.
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: WhenTrue,^and$match individual line boundaries;.does not match newlinescaseSensitive: WhenTrue, 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:
- Avoids dependency resolution failures during builds
- Ensures consistent regex behavior across all build environments
- Eliminates external package update surprises
Usage in Codebase
The direct importers are:
- Utils.hs: wraps
mkRegex/subRegexin itssed/sedManyhelpers, 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 interfaceregex-tdfa- TDFA implementation
See Also
- Typography.hs - Uses regex for typographic rewrites
- Utils.hs - Wraps this module in the widely-used
sed/sedManyhelpers - gwernnet.cabal - Build configuration listing this module