Moonshark/runner/lua/string.lua
2025-05-10 13:02:09 -05:00

197 lines
5.0 KiB
Lua

--[[
string.lua - Extended string library functions
]]--
local string_ext = {}
-- ======================================================================
-- STRING UTILITY FUNCTIONS
-- ======================================================================
-- Trim whitespace from both ends
function string_ext.trim(s)
if type(s) ~= "string" then return s end
return s:match("^%s*(.-)%s*$")
end
-- Split string by delimiter
function string_ext.split(s, delimiter)
if type(s) ~= "string" then return {} end
delimiter = delimiter or ","
local result = {}
for match in (s..delimiter):gmatch("(.-)"..delimiter) do
table.insert(result, match)
end
return result
end
-- Check if string starts with prefix
function string_ext.starts_with(s, prefix)
if type(s) ~= "string" or type(prefix) ~= "string" then return false end
return s:sub(1, #prefix) == prefix
end
-- Check if string ends with suffix
function string_ext.ends_with(s, suffix)
if type(s) ~= "string" or type(suffix) ~= "string" then return false end
return suffix == "" or s:sub(-#suffix) == suffix
end
-- Left pad a string
function string_ext.pad_left(s, len, char)
if type(s) ~= "string" or type(len) ~= "number" then return s end
char = char or " "
if #s >= len then return s end
return string.rep(char:sub(1,1), len - #s) .. s
end
-- Right pad a string
function string_ext.pad_right(s, len, char)
if type(s) ~= "string" or type(len) ~= "number" then return s end
char = char or " "
if #s >= len then return s end
return s .. string.rep(char:sub(1,1), len - #s)
end
-- Center a string
function string_ext.center(s, width, char)
if type(s) ~= "string" or width <= #s then return s end
char = char or " "
local pad_len = width - #s
local left_pad = math.floor(pad_len / 2)
local right_pad = pad_len - left_pad
return string.rep(char:sub(1,1), left_pad) .. s .. string.rep(char:sub(1,1), right_pad)
end
-- Count occurrences of substring
function string_ext.count(s, substr)
if type(s) ~= "string" or type(substr) ~= "string" or #substr == 0 then return 0 end
local count, pos = 0, 1
while true do
pos = s:find(substr, pos, true)
if not pos then break end
count = count + 1
pos = pos + 1
end
return count
end
-- Capitalize first letter
function string_ext.capitalize(s)
if type(s) ~= "string" or #s == 0 then return s end
return s:sub(1,1):upper() .. s:sub(2)
end
-- Capitalize all words
function string_ext.title(s)
if type(s) ~= "string" then return s end
return s:gsub("(%w)([%w]*)", function(first, rest)
return first:upper() .. rest:lower()
end)
end
-- Insert string at position
function string_ext.insert(s, pos, insert_str)
if type(s) ~= "string" or type(insert_str) ~= "string" then return s end
pos = math.max(1, math.min(pos, #s + 1))
return s:sub(1, pos - 1) .. insert_str .. s:sub(pos)
end
-- Remove substring
function string_ext.remove(s, start, length)
if type(s) ~= "string" then return s end
length = length or 1
if start < 1 or start > #s then return s end
return s:sub(1, start - 1) .. s:sub(start + length)
end
-- Replace substring once
function string_ext.replace(s, old, new, n)
if type(s) ~= "string" or type(old) ~= "string" or #old == 0 then return s end
new = new or ""
n = n or 1
return s:gsub(old:gsub("[%-%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%1"), new, n)
end
-- Check if string contains substring
function string_ext.contains(s, substr)
if type(s) ~= "string" or type(substr) ~= "string" then return false end
return s:find(substr, 1, true) ~= nil
end
-- Escape pattern magic characters
function string_ext.escape_pattern(s)
if type(s) ~= "string" then return s end
return s:gsub("[%-%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%1")
end
-- Wrap text at specified width
function string_ext.wrap(s, width, indent_first, indent_rest)
if type(s) ~= "string" or type(width) ~= "number" then return s end
width = math.max(1, width)
indent_first = indent_first or ""
indent_rest = indent_rest or indent_first
local result = {}
local line_prefix = indent_first
local pos = 1
while pos <= #s do
local line_width = width - #line_prefix
local end_pos = math.min(pos + line_width - 1, #s)
if end_pos < #s then
local last_space = s:sub(pos, end_pos):match(".*%s()")
if last_space then
end_pos = pos + last_space - 2
end
end
table.insert(result, line_prefix .. s:sub(pos, end_pos))
pos = end_pos + 1
-- Skip leading spaces on next line
while s:sub(pos, pos) == " " do
pos = pos + 1
end
line_prefix = indent_rest
end
return table.concat(result, "\n")
end
-- Limit string length with ellipsis
function string_ext.truncate(s, length, ellipsis)
if type(s) ~= "string" then return s end
ellipsis = ellipsis or "..."
if #s <= length then return s end
return s:sub(1, length - #ellipsis) .. ellipsis
end
-- ======================================================================
-- INSTALL EXTENSIONS INTO STRING LIBRARY
-- ======================================================================
for name, func in pairs(string) do
string_ext[name] = func
end
return string_ext