app.string - String Utilities API

Extended string processing functionality, enhancing Lua’s native string capabilities.

Basic Operations

app.string.trim(str)

Removes leading and trailing whitespace.

app.string.trim("  hello world  ")  -- "hello world"
app.string.trim("\t hello \n")      -- "hello"

app.string.trimLeft(str)

Removes leading whitespace.

app.string.trimLeft("  hello")  -- "hello"

app.string.trimRight(str)

Removes trailing whitespace.

app.string.trimRight("hello  ")  -- "hello"

app.string.split(str, separator)

Splits a string.

Parameters:

  • str (string) - String to split
  • separator (string) - Separator (empty string splits by character)

Returns: array - Array of split parts

app.string.split("a,b,c", ",")     -- {"a", "b", "c"}
app.string.split("hello", "")      -- {"h", "e", "l", "l", "o"}
app.string.split("a::b", "::")     -- {"a", "b"}

app.string.join(array, separator)

Joins an array into a string.

Parameters:

  • array (table) - Array of strings
  • separator (string) - Separator

Returns: string

app.string.join({"a", "b", "c"}, ", ")  -- "a, b, c"
app.string.join({1, 2, 3}, "-")         -- "1-2-3"

Check Methods

app.string.startsWith(str, prefix)

Checks whether a string starts with the specified prefix.

app.string.startsWith("hello", "he")     -- true
app.string.startsWith("hello", "world")  -- false

app.string.endsWith(str, suffix)

Checks whether a string ends with the specified suffix.

app.string.endsWith("hello.txt", ".txt")  -- true
app.string.endsWith("hello", "world")     -- false

app.string.contains(str, substr)

Checks whether a string contains a substring.

app.string.contains("hello world", "world")  -- true
app.string.contains("hello", "x")            -- false

app.string.isEmpty(str)

Checks whether a string is empty or whitespace only.

app.string.isEmpty("")       -- true
app.string.isEmpty("   ")    -- true
app.string.isEmpty("hello")  -- false

Case Conversion

app.string.upper(str)

Converts to uppercase.

app.string.upper("Hello World")  -- "HELLO WORLD"

app.string.lower(str)

Converts to lowercase.

app.string.lower("Hello World")  -- "hello world"

app.string.capitalize(str)

Capitalizes the first letter (rest lowercase).

app.string.capitalize("hello")  -- "Hello"
app.string.capitalize("HELLO")  -- "Hello"

app.string.camelCase(str)

Converts to camelCase.

app.string.camelCase("hello_world")   -- "helloWorld"
app.string.camelCase("hello-world")   -- "helloWorld"
app.string.camelCase("Hello World")   -- "helloWorld"

app.string.snakeCase(str)

Converts to snake_case.

app.string.snakeCase("helloWorld")    -- "hello_world"
app.string.snakeCase("HelloWorld")    -- "hello_world"
app.string.snakeCase("hello-world")   -- "hello_world"

app.string.kebabCase(str)

Converts to kebab-case.

app.string.kebabCase("helloWorld")    -- "hello-world"
app.string.kebabCase("HelloWorld")    -- "hello-world"

Formatting

app.string.format(template, …)

Formats a string (supports %s, %d, %f, %@ placeholders).

app.string.format("Hello, %s!", "World")     -- "Hello, World!"
app.string.format("Value: %d", 42)           -- "Value: 42"
app.string.format("Price: %f", 3.14)         -- "Price: 3.14"

app.string.padLeft(str, length, char?)

Pads the left side with characters.

Parameters:

  • str (string) - Original string
  • length (number) - Target length
  • char (string, optional) - Padding character (default space)
app.string.padLeft("123", 6, "0")  -- "000123"
app.string.padLeft("hi", 5)        -- "   hi"

app.string.padRight(str, length, char?)

Pads the right side with characters.

app.string.padRight("123", 6, "0")  -- "123000"
app.string.padRight("hi", 5)        -- "hi   "

app.string.repeat(str, count)

Repeats a string.

app.string.repeat("ab", 3)  -- "ababab"
app.string.repeat("-", 10)  -- "----------"

app.string.reverse(str)

Reverses a string.

app.string.reverse("hello")  -- "olleh"

Extraction Methods

app.string.substring(str, start, end?)

Extracts a substring. Index starts at 0.

Parameters:

  • str (string) - Original string
  • start (number) - Start position (0-based)
  • end (number, optional) - End position (exclusive, defaults to end of string)
app.string.substring("hello world", 0, 5)   -- "hello"
app.string.substring("hello world", 6)      -- "world"

app.string.charAt(str, index)

Gets the character at a specified position. Index starts at 0.

app.string.charAt("hello", 0)  -- "h"
app.string.charAt("hello", 4)  -- "o"

app.string.indexOf(str, substr)

Finds the position of a substring.

Returns: number - Position (0-based), returns -1 if not found

app.string.indexOf("hello world", "o")      -- 4
app.string.indexOf("hello world", "x")      -- -1

app.string.lastIndexOf(str, substr)

Finds the last occurrence of a substring.

app.string.lastIndexOf("hello world", "o")  -- 7

app.string.length(str)

Gets the string length (character count, supports UTF-8).

app.string.length("hello")   -- 5
app.string.length("你好")    -- 2

Replacement Methods

app.string.replace(str, old, new)

Replaces the first match.

app.string.replace("hello world", "o", "0")  -- "hell0 world"

app.string.replaceAll(str, old, new)

Replaces all matches.

app.string.replaceAll("hello world", "o", "0")  -- "hell0 w0rld"

app.string.remove(str, substr)

Removes the first matching substring.

app.string.remove("hello world", "o")  -- "hell world"

app.string.removeAll(str, substr)

Removes all matching substrings.

app.string.removeAll("hello world", "o")  -- "hell wrld"

Examples

Batch Rename (Formatted)

function MyPlugin:handleFormatRename(context)
    local result = app.dialog.form({
        title = "Batch Rename",
        fields = {
            {type = "text", id = "prefix", label = "Prefix", default = "file_"},
            {type = "number", id = "start", label = "Starting Number", default = 1},
            {type = "number", id = "digits", label = "Number Digits", default = 3}
        }
    })

    if not result then return end

    local n = result.start
    for _, file in ipairs(context.selectedFiles) do
        local ext = app.path.extension(file)

        -- Generate number
        local numStr = app.string.padLeft(tostring(n), result.digits, "0")
        local newName = result.prefix .. numStr

        if ext ~= "" then
            newName = newName .. "." .. ext
        end

        local newPath = app.path.join(app.path.dirname(file), newName)
        app.file.move(file, newPath)
        n = n + 1
    end
end

File Name Cleanup

function MyPlugin:handleCleanFilenames(context)
    for _, file in ipairs(context.selectedFiles) do
        local name = app.path.basename(file)
        local cleanName = name

        -- Trim leading and trailing whitespace
        cleanName = app.string.trim(cleanName)

        -- Replace multiple spaces with a single space
        while app.string.contains(cleanName, "  ") do
            cleanName = app.string.replaceAll(cleanName, "  ", " ")
        end

        -- Replace special characters
        cleanName = app.string.replaceAll(cleanName, ":", "-")
        cleanName = app.string.replaceAll(cleanName, "/", "-")

        if cleanName ~= name then
            local newPath = app.path.join(app.path.dirname(file), cleanName)
            app.file.move(file, newPath)
        end
    end
end

Case Conversion for File Names

function MyPlugin:handleConvertCase(context)
    local result = app.dialog.form({
        title = "Case Conversion",
        fields = {
            {type = "dropdown", id = "style", label = "Target Format",
             options = {"camelCase", "snake_case", "kebab-case"},
             default = "camelCase"}
        }
    })

    if not result then return end

    for _, file in ipairs(context.selectedFiles) do
        local name = app.path.name(file)
        local ext = app.path.extension(file)
        local newName

        if result.style == "camelCase" then
            newName = app.string.camelCase(name)
        elseif result.style == "snake_case" then
            newName = app.string.snakeCase(name)
        else
            newName = app.string.kebabCase(name)
        end

        if ext ~= "" then
            newName = newName .. "." .. ext
        end

        local newPath = app.path.join(app.path.dirname(file), newName)
        app.file.move(file, newPath)
    end
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