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 matchpattern(string) - Regular expression patternoptions(table, optional):ignoreCase(boolean) - Case-insensitive matchingmultiline(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 stringpattern(string) - Regular expression patternreplacement(string) - Replacement content (supports \(1, \)2 back-references)options(table, optional): Same asmatch
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 splitpattern(string) - Separator patternoptions(table, optional): Same asmatch
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