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