Beta documentation. This is an early preview — content is still in active development. Feedback helps shape the final release. Share your thoughts or join the discussion.

String Utilities

The `str` library handles common string operations. All functions are UTF-8 safe — they work correctly with international text, emoji, and special characters.

On this page

String manipulation made safe

The str library handles common string operations. All functions are UTF-8 safe — they work correctly with international text, emoji, and special characters.

Function reference

Function Example Result
str.split(s, sep) str.split("a,b,c", ",") { "a", "b", "c" }
str.trim(s) str.trim(" hello ") "hello"
str.contains(s, sub) str.contains("hello world", "ell") true
str.starts_with(s, p) str.starts_with("/api/users", "/api") true
str.ends_with(s, suf) str.ends_with("file.lua", ".lua") true
str.limit(s, n, end?) str.limit("hello world", 8) "hello wo..."
str.replace(s, old, new) str.replace("hello world", "world", "Lua") "hello Lua"
str.lcfirst(s) str.lcfirst("Hello") "hello"
str.ucfirst(s) str.ucfirst("hello") "Hello"
str.ucwords(s) str.ucwords("hello world") "Hello World"

str.split — Parse lists

-- Parse comma-separated tags
local tags = str.split(req.post.tags, ",")
for _, tag in ipairs(tags) do
    tag = str.trim(tag)    -- clean whitespace
    table.insert(clean_tags, str.lcfirst(tag))
end

-- Split a path
local parts = str.split(req.path, "/")
-- "/blog/2026/hello" → { "", "blog", "2026", "hello" }

str.contains — Quick checks

-- Check if a URL is an API path
if str.contains(req.path, "/api/") then
    -- apply rate limiting
end

-- Check user agent
if str.contains(req.headers["user-agent"] or "", "bot") then
    log.info("Bot detected: " .. env.remote_ip)
end

str.starts_with / str.ends_with — Pattern matching

-- Route guards
if str.starts_with(req.path, "/admin") and not env.is_admin then
    return ctx:error("Forbidden", 403)
end

-- File type check
if str.ends_with(filename, ".lua") then
    -- handle Lua file
elseif str.ends_with(filename, ".md") then
    -- handle markdown
end

str.replace — Find and replace

-- Clean user input
local clean = str.replace(raw_input, "<script>", "")
clean = str.replace(clean, "</script>", "")

-- Template-like substitution
local template = "Hello, {name}! Your order #{id} is ready."
local message = str.replace(template, "{name}", user.name)
message = str.replace(message, "{id}", tostring(order.id))

str.limit — Truncate for previews

-- Blog post excerpt
local excerpt = str.limit(post.content, 200)
-- → first 200 chars + "..."

-- Custom ending
local title = str.limit(long_title, 50, "…")

str.ucfirst / str.lcfirst — Case normalization

-- Normalize user input
local name = str.ucfirst(str.trim(req.post.name))
-- "john" → "John"
-- "  ALICE  " → "Alice"

-- Generate display labels
local label = str.ucwords(str.replace(status, "_", " "))
-- "order_shipped" → "Order Shipped"

Practical: parsing a tag input field

-- "  Lua,  Wapka, API, tutorial  " → { "lua", "wapka", "api", "tutorial" }
function parseTags(input)
    local tags = {}
    for _, tag in ipairs(str.split(input, ",")) do
        local clean = str.trim(str.lcfirst(tag))
        if clean ~= "" then
            table.insert(tags, clean)
        end
    end
    return tags
end

app:post("/posts/create", function(ctx)
    local tags = parseTags(req.post.tags)
    -- tags = { "lua", "wapka", "api", "tutorial" }
end)

Next: Logging — debug and monitor your app.

Previous Hash & Crypto Next Logging