Files
wnsrc/lua/includes/extensions/string.lua
lifestorm 94063e4369 Upload
2024-08-04 22:55:00 +03:00

462 lines
13 KiB
Lua

--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local string = string
local math = math
--[[---------------------------------------------------------
Name: string.ToTable( string )
-----------------------------------------------------------]]
function string.ToTable( input )
local tbl = {}
-- For numbers, as some addons do this..
local str = tostring( input )
for i = 1, #str do
tbl[i] = string.sub( str, i, i )
end
return tbl
end
--[[---------------------------------------------------------
Name: string.JavascriptSafe( string )
Desc: Takes a string and escapes it for insertion in to a JavaScript string
-----------------------------------------------------------]]
local javascript_escape_replacements = {
["\\"] = "\\\\",
["\0"] = "\\x00" ,
["\b"] = "\\b" ,
["\t"] = "\\t" ,
["\n"] = "\\n" ,
["\v"] = "\\v" ,
["\f"] = "\\f" ,
["\r"] = "\\r" ,
["\""] = "\\\"",
["\'"] = "\\\'",
["`"] = "\\`",
["$"] = "\\$",
["{"] = "\\{",
["}"] = "\\}"
}
function string.JavascriptSafe( str )
str = string.gsub( str, ".", javascript_escape_replacements )
-- U+2028 and U+2029 are treated as line separators in JavaScript, handle separately as they aren't single-byte
str = string.gsub( str, "\226\128\168", "\\\226\128\168" )
str = string.gsub( str, "\226\128\169", "\\\226\128\169" )
return str
end
--[[---------------------------------------------------------
Name: string.PatternSafe( string )
Desc: Takes a string and escapes it for insertion in to a Lua pattern
-----------------------------------------------------------]]
local pattern_escape_replacements = {
["("] = "%(",
[")"] = "%)",
["."] = "%.",
["%"] = "%%",
["+"] = "%+",
["-"] = "%-",
["*"] = "%*",
["?"] = "%?",
["["] = "%[",
["]"] = "%]",
["^"] = "%^",
["$"] = "%$",
["\0"] = "%z"
}
function string.PatternSafe( str )
return ( string.gsub( str, ".", pattern_escape_replacements ) )
end
--[[---------------------------------------------------------
Name: explode(seperator ,string)
Desc: Takes a string and turns it into a table
Usage: string.explode( " ", "Seperate this string")
-----------------------------------------------------------]]
local totable = string.ToTable
local string_sub = string.sub
local string_find = string.find
local string_len = string.len
function string.Explode( separator, str, withpattern )
if ( separator == "" ) then return totable( str ) end
if ( withpattern == nil ) then withpattern = false end
local ret = {}
local current_pos = 1
for i = 1, string_len( str ) do
local start_pos, end_pos = string_find( str, separator, current_pos, not withpattern )
if ( not start_pos ) then break end
ret[ i ] = string_sub( str, current_pos, start_pos - 1 )
current_pos = end_pos + 1
end
ret[ #ret + 1 ] = string_sub( str, current_pos )
return ret
end
function string.Split( str, delimiter )
return string.Explode( delimiter, str )
end
--[[---------------------------------------------------------
Name: Implode( seperator, Table)
Desc: Takes a table and turns it into a string
Usage: string.Implode( " ", { "This", "Is", "A", "Table" } )
-----------------------------------------------------------]]
function string.Implode( seperator, Table ) return
table.concat( Table, seperator )
end
--[[---------------------------------------------------------
Name: GetExtensionFromFilename( path )
Desc: Returns extension from path
Usage: string.GetExtensionFromFilename("garrysmod/lua/modules/string.lua")
-----------------------------------------------------------]]
function string.GetExtensionFromFilename( path )
for i = #path, 1, -1 do
local c = string.sub( path, i, i )
if ( c == "/" or c == "\\" ) then return nil end
if ( c == "." ) then return string.sub( path, i + 1 ) end
end
return nil
end
--[[---------------------------------------------------------
Name: StripExtension( path )
-----------------------------------------------------------]]
function string.StripExtension( path )
for i = #path, 1, -1 do
local c = string.sub( path, i, i )
if ( c == "/" or c == "\\" ) then return path end
if ( c == "." ) then return string.sub( path, 1, i - 1 ) end
end
return path
end
--[[---------------------------------------------------------
Name: GetPathFromFilename( path )
Desc: Returns path from filepath
Usage: string.GetPathFromFilename("garrysmod/lua/modules/string.lua")
-----------------------------------------------------------]]
function string.GetPathFromFilename( path )
for i = #path, 1, -1 do
local c = string.sub( path, i, i )
if ( c == "/" or c == "\\" ) then return string.sub( path, 1, i ) end
end
return ""
end
--[[---------------------------------------------------------
Name: GetFileFromFilename( path )
Desc: Returns file with extension from path
Usage: string.GetFileFromFilename("garrysmod/lua/modules/string.lua")
-----------------------------------------------------------]]
function string.GetFileFromFilename( path )
for i = #path, 1, -1 do
local c = string.sub( path, i, i )
if ( c == "/" or c == "\\" ) then return string.sub( path, i + 1 ) end
end
return path
end
--[[-----------------------------------------------------------------
Name: FormattedTime( TimeInSeconds, Format )
Desc: Given a time in seconds, returns formatted time
If 'Format' is not specified the function returns a table
conatining values for hours, mins, secs, ms
Examples: string.FormattedTime( 123.456, "%02i:%02i:%02i") ==> "02:03:45"
string.FormattedTime( 123.456, "%02i:%02i") ==> "02:03"
string.FormattedTime( 123.456, "%2i:%02i") ==> " 2:03"
string.FormattedTime( 123.456 ) ==> { h = 0, m = 2, s = 3, ms = 45 }
-------------------------------------------------------------------]]
function string.FormattedTime( seconds, format )
if ( not seconds ) then seconds = 0 end
local hours = math.floor( seconds / 3600 )
local minutes = math.floor( ( seconds / 60 ) % 60 )
local millisecs = ( seconds - math.floor( seconds ) ) * 100
seconds = math.floor( seconds % 60 )
if ( format ) then
return string.format( format, minutes, seconds, millisecs )
else
return { h = hours, m = minutes, s = seconds, ms = millisecs }
end
end
--[[---------------------------------------------------------
Name: Old time functions
-----------------------------------------------------------]]
function string.ToMinutesSecondsMilliseconds( TimeInSeconds ) return string.FormattedTime( TimeInSeconds, "%02i:%02i:%02i" ) end
function string.ToMinutesSeconds( TimeInSeconds ) return string.FormattedTime( TimeInSeconds, "%02i:%02i" ) end
local function pluralizeString( str, quantity )
return str .. ( ( quantity ~= 1 ) and "s" or "" )
end
function string.NiceTime( seconds )
if ( seconds == nil ) then return "a few seconds" end
if ( seconds < 60 ) then
local t = math.floor( seconds )
return t .. pluralizeString( " second", t )
end
if ( seconds < 60 * 60 ) then
local t = math.floor( seconds / 60 )
return t .. pluralizeString( " minute", t )
end
if ( seconds < 60 * 60 * 24 ) then
local t = math.floor( seconds / (60 * 60) )
return t .. pluralizeString( " hour", t )
end
if ( seconds < 60 * 60 * 24 * 7 ) then
local t = math.floor( seconds / ( 60 * 60 * 24 ) )
return t .. pluralizeString( " day", t )
end
if ( seconds < 60 * 60 * 24 * 365 ) then
local t = math.floor( seconds / ( 60 * 60 * 24 * 7 ) )
return t .. pluralizeString( " week", t )
end
local t = math.floor( seconds / ( 60 * 60 * 24 * 365 ) )
return t .. pluralizeString( " year", t )
end
function string.Left( str, num ) return string.sub( str, 1, num ) end
function string.Right( str, num ) return string.sub( str, -num ) end
function string.Replace( str, tofind, toreplace )
local tbl = string.Explode( tofind, str )
if ( tbl[ 1 ] ) then return table.concat( tbl, toreplace ) end
return str
end
--[[---------------------------------------------------------
Name: Trim( s )
Desc: Removes leading and trailing spaces from a string.
Optionally pass char to trim that character from the ends instead of space
-----------------------------------------------------------]]
function string.Trim( s, char )
if ( char ) then char = string.PatternSafe( char ) else char = "%s" end
return string.match( s, "^" .. char .. "*(.-)" .. char .. "*$" ) or s
end
--[[---------------------------------------------------------
Name: TrimRight( s )
Desc: Removes trailing spaces from a string.
Optionally pass char to trim that character from the ends instead of space
-----------------------------------------------------------]]
function string.TrimRight( s, char )
if ( char ) then char = string.PatternSafe( char ) else char = "%s" end
return string.match( s, "^(.-)" .. char .. "*$" ) or s
end
--[[---------------------------------------------------------
Name: TrimLeft( s )
Desc: Removes leading spaces from a string.
Optionally pass char to trim that character from the ends instead of space
-----------------------------------------------------------]]
function string.TrimLeft( s, char )
if ( char ) then char = string.PatternSafe( char ) else char = "%s" end
return string.match( s, "^" .. char .. "*(.+)$" ) or s
end
function string.NiceSize( size )
size = tonumber( size )
if ( size <= 0 ) then return "0" end
if ( size < 1000 ) then return size .. " Bytes" end
if ( size < 1000 * 1000 ) then return math.Round( size / 1000, 2 ) .. " KB" end
if ( size < 1000 * 1000 * 1000 ) then return math.Round( size / ( 1000 * 1000 ), 2 ) .. " MB" end
return math.Round( size / ( 1000 * 1000 * 1000 ), 2 ) .. " GB"
end
-- Note: These use Lua index numbering, not what you'd expect
-- ie they start from 1, not 0.
function string.SetChar( s, k, v )
return string.sub( s, 0, k - 1 ) .. v .. string.sub( s, k + 1 )
end
function string.GetChar( s, k )
return string.sub( s, k, k )
end
local meta = getmetatable( "" )
function meta:__index( key )
local val = string[ key ]
if ( val ~= nil ) then
return val
elseif ( tonumber( key ) ) then
return string.sub( self, key, key )
end
end
function string.StartsWith( str, start )
return string.sub( str, 1, string.len( start ) ) == start
end
string.StartWith = string.StartsWith
function string.EndsWith( str, endStr )
return endStr == "" or string.sub( str, -string.len( endStr ) ) == endStr
end
function string.FromColor( color )
return Format( "%i %i %i %i", color.r, color.g, color.b, color.a )
end
function string.ToColor( str )
local r, g, b, a = string.match( str, "(%d+) (%d+) (%d+) (%d+)" )
local col = Color( 255, 255, 255, 255 )
col.r = tonumber( r ) or 255
col.g = tonumber( g ) or 255
col.b = tonumber( b ) or 255
col.a = tonumber( a ) or 255
return col
end
function string.Comma( number, str )
if ( str ~= nil and not isstring( str ) ) then
error( "bad argument #2 to 'string.Comma' (string expected, got " .. type( str ) .. ")" )
elseif ( str ~= nil and string.match( str, "%d" ) ~= nil ) then
error( "bad argument #2 to 'string.Comma' (non-numerical values expected, got " .. str .. ")" )
end
local replace = str == nil and "%1,%2" or "%1" .. str .. "%2"
if ( isnumber( number ) ) then
number = string.format( "%f", number )
number = string.match( number, "^(.-)%.?0*$" ) -- Remove trailing zeros
end
local index = -1
while index ~= 0 do number, index = string.gsub( number, "^(-?%d+)(%d%d%d)", replace ) end
return number
end
function string.Interpolate( str, lookuptable )
return ( string.gsub( str, "{([_%a][_%w]*)}", lookuptable ) )
end
function string.CardinalToOrdinal( cardinal )
local basedigit = cardinal % 10
if ( basedigit == 1 ) then
if ( cardinal % 100 == 11 ) then
return cardinal .. "th"
end
return cardinal .. "st"
elseif ( basedigit == 2 ) then
if ( cardinal % 100 == 12 ) then
return cardinal .. "th"
end
return cardinal .. "nd"
elseif ( basedigit == 3 ) then
if ( cardinal % 100 == 13 ) then
return cardinal .. "th"
end
return cardinal .. "rd"
end
return cardinal .. "th"
end
function string.NiceName( name )
name = name:Replace( "_", " " )
-- Try to split text into words, where words would start with single uppercase character
local newParts = {}
for id, str in ipairs( string.Explode( " ", name ) ) do
local wordStart = 1
for i = 2, str:len() do
local c = str[ i ]
if ( c:upper() == c ) then
local toAdd = str:sub( wordStart, i - 1 )
if ( toAdd:upper() == toAdd ) then continue end
table.insert( newParts, toAdd )
wordStart = i
end
end
table.insert( newParts, str:sub( wordStart, str:len() ) )
end
-- Capitalize
--[[
for i, word in ipairs( newParts ) do
if ( #word == 1 ) then
newParts[i] = string.upper( word )
else
newParts[i] = string.upper( string.sub( word, 1, 1 ) ) .. string.sub( word, 2 )
end
end
return table.concat( newParts, " " )]]
local ret = table.concat( newParts, " " )
ret = string.upper( string.sub( ret, 1, 1 ) ) .. string.sub( ret, 2 )
return ret
end