LiquidProxy Lua Edition
at master 164 lines 4.3 kB view raw
1--[[ 2notice that, 3while this does override the 'string' and add some extra stuff, 4it does not explicitly replace the default string metatable __index 5to do that, require 'ext.meta' (or do it yourself) 6--]] 7local string = {} 8for k,v in pairs(require 'string') do string[k] = v end 9 10local table = require 'ext.table' 11 12-- table.concat(string.split(a,b),b) == a 13function string.split(s, exp) 14 exp = exp or '' 15 s = tostring(s) 16 local t = table() 17 -- handle the exp='' case 18 if exp == '' then 19 for i=1,#s do 20 t:insert(s:sub(i,i)) 21 end 22 else 23 local searchpos = 1 24 local start, fin = s:find(exp, searchpos) 25 while start do 26 t:insert(s:sub(searchpos, start-1)) 27 searchpos = fin+1 28 start, fin = s:find(exp, searchpos) 29 end 30 t:insert(s:sub(searchpos)) 31 end 32 return t 33end 34 35function string.trim(s) 36 return s:match('^%s*(.-)%s*$') 37end 38 39-- should this wrap in a table? 40function string.bytes(s) 41 return table{s:byte(1,#s)} 42end 43 44string.load = load or loadstring 45 46--[[ 47-- drifting further from standards... 48-- this string-converts everything concat'd (no more errors, no more print(a,b,c)'s) 49getmetatable('').__concat = function(a,b) 50 return tostring(a)..tostring(b) 51end 52--]] 53 54-- a C++-ized accessor to subsets 55-- indexes are zero-based inclusive 56-- sizes are zero-based-exclusive (or one-based-inclusive depending on how you think about it) 57-- parameters are (index, size) rather than (start index, end index) 58function string.csub(d, start, size) 59 if not size then return string.sub(d, start + 1) end -- til-the-end 60 return string.sub(d, start + 1, start + size) 61end 62 63--d = string data 64--l = length of a column. default 32 65--w = hex word size. default 1 66--c = extra column space. default 8 67function string.hexdump(d, l, w, c) 68 d = tostring(d) 69 l = tonumber(l) 70 w = tonumber(w) 71 c = tonumber(c) 72 if not l or l < 1 then l = 32 end 73 if not w or w < 1 then w = 1 end 74 if not c or c < 1 then c = 8 end 75 local s = table() 76 local rhs = table() 77 local col = 0 78 for i=1,#d,w do 79 if i % l == 1 then 80 s:insert(string.format('%.8x ', (i-1))) 81 rhs = table() 82 col = 1 83 end 84 s:insert' ' 85 for j=w,1,-1 do 86 local e = i+j-1 87 local sub = d:sub(e,e) 88 if #sub > 0 then 89 local b = string.byte(sub) 90 s:insert(string.format('%.2x', b)) 91 rhs:insert(b >= 32 and sub or '.') 92 end 93 end 94 if col % c == 0 then 95 s:insert' ' 96 end 97 if (i + w - 1) % l == 0 or i+w>#d then 98 s:insert' ' 99 s:insert(rhs:concat()) 100 end 101 if (i + w - 1) % l == 0 then 102 s:insert'\n' 103 end 104 col = col + 1 105 end 106 return s:concat() 107end 108 109-- escape for pattern matching 110local escapeFind = '[' .. ([[^$()%.[]*+-?]]):gsub('.', '%%%1') .. ']' 111function string.patescape(s) 112 return (s:gsub(escapeFind, '%%%1')) 113end 114 115-- this is a common function, especially as a __concat metamethod 116-- it is nearly table.concat, except table.concat errors upon non-string/number instead of calling tostring() automatically 117-- (should I change table.concat's default behavior and use that instead? nah, because why require a table creation.) 118-- tempted to make this ext.op.concat ... but that's specifically a binary op ... and that shouldn't call tostring() while this should ... 119-- maybe I should move this to ext.op as 'tostringconcat' or something? 120function string.concat(...) 121 local n = select('#', ...) 122 if n == 0 then return end -- base-case nil or "" ? 123 local s = tostring((...)) 124 if n == 1 then return s end 125 return s .. string.concat(select(2, ...)) 126end 127 128-- another common __tostring metamethod 129-- since luajit doesn't support __name metafield 130function string:nametostring() 131 -- NOTICE this will break for anything that overrides its __metatable metafield 132 local mt = getmetatable(self) 133 134 -- invoke a 'rawtostring' call / get the builtin 'tostring' result 135 setmetatable(self, nil) 136 local s = tostring(self) 137 setmetatable(self, mt) 138 139 local name = mt.__name 140 return name and tostring(name)..s:sub(6) or s 141end 142 143-- I use this too often .... 144function string.hex(s, uppercase) 145 local fmt = uppercase and '%02X' or '%02x' 146 return (tostring(s):gsub('.', function(c) 147 return fmt:format(c:byte()) 148 end)) 149end 150 151function string.unhex(h) 152 if bit.band(#h, 1) == 1 153 or h:find'[^0-9a-fA-F]' 154 then 155 return nil, "string is not hex" 156 end 157 return h:gsub('..', function(d) 158 return string.char(assert(tonumber(d, 16))) 159 end) 160end 161 162-- TODO other encoders? 163 164return string