197 lines
5.0 KiB
Lua
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 |