app.regex - Regular Expression API

Regular expression matching and replacement. Based on NSRegularExpression.

Match Methods

app.regex.match(str, pattern, options?)

Gets the first match and its capture groups.

Parameters:

  • str (string) - String to match
  • pattern (string) - Regular expression pattern
  • options (table, optional):
    • ignoreCase (boolean) - Case-insensitive matching
    • multiline (boolean) - Multiline mode (^ and $ match line boundaries)
    • dotMatchesLineSeparators (boolean) - Dot matches line separators

Returns: table|nil - Match result or nil

-- Simple match
local m = app.regex.match("hello world", "\\w+")
-- { match = "hello", start = 0, ["end"] = 5 }

-- With capture groups
local m = app.regex.match("hello world", "(\\w+) (\\w+)")
-- {
--     match = "hello world",
--     start = 0,
--     ["end"] = 11,
--     groups = {"hello", "world"}
-- }

-- Case-insensitive
local m = app.regex.match("Hello", "hello", {ignoreCase = true})

app.regex.matchAll(str, pattern, options?)

Gets all matches.

Parameters: Same as match

Returns: array - Array of match results

local matches = app.regex.matchAll("a1b2c3", "\\d")
-- {
--     { match = "1", start = 1, ["end"] = 2 },
--     { match = "2", start = 3, ["end"] = 4 },
--     { match = "3", start = 5, ["end"] = 6 }
-- }

app.regex.test(str, pattern, options?)

Tests whether a string matches.

Parameters: Same as match

Returns: boolean

app.regex.test("hello@example.com", "^[\\w.-]+@[\\w.-]+\\.\\w+$")  -- true
app.regex.test("invalid-email", "^[\\w.-]+@[\\w.-]+\\.\\w+$")      -- false

Extraction Methods

app.regex.find(str, pattern, options?)

Returns the first matching string.

Parameters: Same as match

Returns: string|nil - Matched string or nil

local word = app.regex.find("hello world", "\\w+")
-- "hello"

app.regex.findAll(str, pattern, options?)

Returns all matching strings.

Parameters: Same as match

Returns: array - Array of strings

local numbers = app.regex.findAll("a1b2c3", "\\d")
-- {"1", "2", "3"}

local words = app.regex.findAll("hello world", "\\w+")
-- {"hello", "world"}

app.regex.groups(str, pattern, options?)

Returns the capture groups of the first match.

Parameters: Same as match

Returns: array|nil - Array of capture groups or nil

local groups = app.regex.groups("hello world", "(\\w+) (\\w+)")
-- {"hello", "world"}

local parts = app.regex.groups("2024-01-15", "(\\d{4})-(\\d{2})-(\\d{2})")
-- {"2024", "01", "15"}

Replacement Methods

app.regex.replace(str, pattern, replacement, options?)

Replaces the first match.

Parameters:

  • str (string) - Original string
  • pattern (string) - Regular expression pattern
  • replacement (string) - Replacement content (supports \(1, \)2 back-references)
  • options (table, optional): Same as match

Returns: string - String after replacement

-- Replace the first digit
app.regex.replace("a1b2c3", "\\d", "X")  -- "aXb2c3"

-- Using back-references
app.regex.replace("hello world", "(\\w+)", "[$1]")  -- "[hello] world"

app.regex.replaceAll(str, pattern, replacement, options?)

Replaces all matches.

Parameters: Same as replace

Returns: string - String after replacement

-- Replace all digits
app.regex.replaceAll("a1b2c3", "\\d", "X")  -- "aXbXcX"

-- Replace all whitespace with underscores
app.regex.replaceAll("hello world", "\\s+", "_")  -- "hello_world"

-- Using back-references
app.regex.replaceAll("hello world", "(\\w+)", "[$1]")  -- "[hello] [world]"

Split Methods

app.regex.split(str, pattern, options?)

Splits a string by a regular expression.

Parameters:

  • str (string) - String to split
  • pattern (string) - Separator pattern
  • options (table, optional): Same as match

Returns: array - Array of split parts

app.regex.split("a1b2c3", "\\d")           -- {"a", "b", "c", ""}
app.regex.split("a  b   c", "\\s+")        -- {"a", "b", "c"}
app.regex.split("one,two;three", "[,;]")   -- {"one", "two", "three"}

Options Reference

Option Description
ignoreCase Case-insensitive matching
multiline Multiline mode, ^ and $ match the beginning and end of each line
dotMatchesLineSeparators . can match line separators

Common Patterns

-- Email
local EMAIL = "^[\\w.-]+@[\\w.-]+\\.\\w+$"

-- URL
local URL = "^https?://[\\w.-]+(?:/[\\w./-]*)?$"

-- IP Address
local IP = "^(?:\\d{1,3}\\.){3}\\d{1,3}$"

-- Date (YYYY-MM-DD)
local DATE = "^\\d{4}-\\d{2}-\\d{2}$"

-- Hex Color
local HEX_COLOR = "^#?[0-9A-Fa-f]{6}$"

-- File Extension
local FILE_EXT = "\\.(\\w+)$"

Examples

Extract Numbers from File Names

function MyPlugin:handleExtractNumbers(context)
    local results = {}

    for _, file in ipairs(context.selectedFiles) do
        local name = app.path.basename(file)
        local numbers = app.regex.findAll(name, "\\d+")

        if #numbers > 0 then
            table.insert(results, name .. ": " .. table.concat(numbers, ", "))
        end
    end

    if #results > 0 then
        app.dialog.alert({
            title = "Extraction Results",
            message = table.concat(results, "\n")
        })
    else
        app.dialog.alert({title = "Notice", message = "No numbers found"})
    end
end

Batch Rename (Regex Replace)

function MyPlugin:handleRegexRename(context)
    local result = app.dialog.form({
        title = "Regex Rename",
        fields = {
            {type = "text", id = "pattern", label = "Match Pattern", default = ""},
            {type = "text", id = "replacement", label = "Replace With", default = ""},
            {type = "checkbox", id = "ignoreCase", label = "Ignore Case", default = false}
        }
    })

    if not result or result.pattern == "" then return end

    -- Validate regex (try matching an empty string)
    local valid = app.regex.test("", result.pattern) ~= nil or app.regex.test("test", result.pattern) ~= nil

    local renamed = 0
    for _, file in ipairs(context.selectedFiles) do
        local name = app.path.basename(file)
        local newName = app.regex.replaceAll(name, result.pattern, result.replacement, {
            ignoreCase = result.ignoreCase
        })

        if newName ~= name then
            local newPath = app.path.join(app.path.dirname(file), newName)
            if app.file.move(file, newPath) then
                renamed = renamed + 1
            end
        end
    end

    app.notification.show("Done", "Renamed " .. renamed .. " files")
end

Validate File Name Format

function MyPlugin:validateFilenames(context)
    -- Validate format: YYYY-MM-DD_description.ext
    local pattern = "^\\d{4}-\\d{2}-\\d{2}_[\\w-]+\\.\\w+$"

    local invalid = {}
    for _, file in ipairs(context.selectedFiles) do
        local name = app.path.basename(file)
        if not app.regex.test(name, pattern) then
            table.insert(invalid, name)
        end
    end

    if #invalid == 0 then
        app.dialog.alert({title = "Validation Passed", message = "All file names have the correct format"})
    else
        app.dialog.alert({
            title = "Format Error",
            message = "The following file names do not match the format:\n" .. table.concat(invalid, "\n")
        })
    end
end

Parse Log File

function MyPlugin:parseLogLine(line)
    -- Log format: [2024-01-15 10:30:45] [INFO] Message here
    local pattern = "^\\[(\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2})\\] \\[(\\w+)\\] (.+)$"
    local groups = app.regex.groups(line, pattern)

    if groups then
        return {
            timestamp = groups[1],
            level = groups[2],
            message = groups[3]
        }
    end
    return nil
end
Developer Documentation
User Guide
Getting Started Script Menus FAQ
Script Development
Development Guide
Plugin Development
Quick Start Development Guide Example Plugins
API Reference
Overview API Query Plugin Info Logging Finder Context Plugin Settings Internationalization
UI & Interaction
Dialog Progress Notification Chooser WebView Status Bar Dock
Files & Paths
File Operations Path Utilities Finder Actions Trash Extended Attributes Metadata File Watcher
Data Formats
JSON Plist CSV XML PDF Image
Text & Encoding
String Regex Date & Time Color Crypto
System
Shell Commands Process Application System Info AppleScript Shortcuts
System Info
Network Power/Battery Screen/Appearance Audio Bluetooth Location
Network
HTTP WebSocket URL
Input & Clipboard
Keyboard Mouse Hotkey Clipboard Window
Storage
SQLite Keychain UserDefaults
Media
OCR QR Code
Utilities
Archive UTI Share Timer Wake Lock Thread