parseRegexpPattern function

({bool hasReplacement, String pattern, String replacement})? parseRegexpPattern(
  1. String pattern
)

Parse regexp pattern string into pattern and replacement parts

Extracts the pattern and optional replacement from a regexp transform string. Handles escaped slashes and special characters.

Parameters

  • pattern - Regexp string in format /pattern/ or /pattern/replacement/

Returns

A record with:

  • pattern - The regular expression pattern
  • replacement - The replacement string (empty for extraction mode)

Returns null if the format is invalid (no slashes found).

Format

  • Extraction: /pattern/(pattern: 'pattern', replacement: '')
  • Replacement: /pattern/replacement/(pattern: 'pattern', replacement: 'replacement')

Special Handling

  • Escaped slashes: \/ in patterns are preserved
  • \ALL keyword: Converted to ^[\s\S]*$ for full string matching
  • Escaped characters: \/, \; are unescaped in replacement

Examples

parseRegexpPattern(r'/\d+/');
// Returns: (pattern: r'\d+', replacement: '')

parseRegexpPattern(r'/hello/world/');
// Returns: (pattern: 'hello', replacement: 'world')

parseRegexpPattern(r'/\ALL/replaced/');
// Returns: (pattern: r'^[\s\S]*$', replacement: 'replaced')

parseRegexpPattern('invalid');
// Returns: null

Implementation

({String pattern, String replacement, bool hasReplacement})? parseRegexpPattern(
    String pattern) {
  // Split by unescaped slashes
  final parts = pattern.split(RegExp(r'(?<!\\)/'));

  // Remove leading empty string (before first /)
  if (parts.isNotEmpty && parts[0].isEmpty) {
    parts.removeAt(0);
  }

  // Track if there was a trailing slash (indicates replacement mode)
  final hasTrailingSlash = parts.isNotEmpty && parts[parts.length - 1].isEmpty;

  // Remove trailing empty string (after last /)
  if (hasTrailingSlash) {
    parts.removeLast();
  }

  if (parts.isEmpty) {
    return null;
  }

  // Validate that the pattern is not empty
  if (parts[0].isEmpty) {
    return null;
  }

  // Determine if replacement was provided
  bool hasReplacement;
  if (parts.length == 1) {
    // Only pattern, no replacement
    hasReplacement = false;
    parts.add("");
  } else if (parts.length == 3 && parts[2] == 's') {
    // Special case: /pattern/replacement/s/ means extraction mode (first match only)
    hasReplacement = false;
  } else {
    // Has replacement (even if empty)
    hasReplacement = true;
  }

  // Decode special characters in pattern
  var regexPattern = parts[0];

  // Handle \ALL keyword - matches entire string including newlines
  if (regexPattern.contains(r'\ALL')) {
    regexPattern = regexPattern.replaceAll(r'\ALL', r'^[\s\S]*$');
  }

  // Decode escaped characters in replacement
  final replacementStr = parts[1].replaceAll(r'\/', '/').replaceAll(r'\;', ';');

  return (
    pattern: regexPattern,
    replacement: replacementStr,
    hasReplacement: hasReplacement
  );
}